home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / clisp-li.000 / clisp-li / clisp-1996-07-22 / src / editor.lsp < prev    next >
Encoding:
Lisp/Scheme  |  1996-06-05  |  114.2 KB  |  2,954 lines

  1. (in-package "LISP")
  2. (export '(editor ed *use-ed*))
  3. (pushnew 'editor *features*)
  4. #+(or DOS OS/2) (eval-when (compile load eval) (pushnew 'dose *features*))
  5. (in-package "EDITOR")
  6.  
  7. ;###############################################################################
  8. ;;;; Screen-Verwaltung, dritte Version
  9. ;;;;
  10. ;;;; Michael Stoll, Februar 1992
  11. ;;;; Bruno Haible, Mai 1992
  12. ;;;;
  13. ;;;; Spezifikation siehe SCREEN2.DOC
  14.  
  15. (defvar *window*) ; aktuelles Ausgabefenster
  16. (defvar global-screen-height) ; H÷he des Fensters
  17. (defvar global-screen-width)  ; Breite des Fensters
  18. (defvar blanks) ; Array voller Spaces
  19.  
  20. (defmacro with-window (&body body)
  21.   `(LET* ((*WINDOW* (SCREEN:MAKE-WINDOW))
  22.           #+AMIGA (*KEYBOARD-INPUT* (SCREEN::MAKE-KEYBOARD-STREAM *WINDOW*))
  23.          )
  24.      (UNWIND-PROTECT
  25.        (MULTIPLE-VALUE-BIND (GLOBAL-SCREEN-HEIGHT GLOBAL-SCREEN-WIDTH) (SCREEN:WINDOW-SIZE *WINDOW*)
  26.          (LET ((BLANKS (MAKE-STRING GLOBAL-SCREEN-WIDTH :INITIAL-ELEMENT #\SPACE)))
  27.            ,@body
  28.        ) )
  29.        #+AMIGA (CLOSE *KEYBOARD-INPUT*)
  30.        #+AMIGA (SCREEN:WINDOW-CURSOR-ON *WINDOW*)
  31.        (CLOSE *WINDOW*)
  32.    ) )
  33. )
  34.  
  35. ;;; ZunΣchst einige Macros zur Bildschirmsteuerung
  36.  
  37. (defmacro bell () `(WRITE-CHAR #\Bell *TERMINAL-IO*))
  38.  
  39. (defmacro screen-set-cursor (lin col)
  40.   `(SCREEN:SET-WINDOW-CURSOR-POSITION *WINDOW* ,lin ,col)
  41. )
  42.  
  43. (defmacro screen-home ()
  44.   `(SCREEN-SET-CURSOR 0 0)
  45. )
  46.  
  47. (defmacro screen-clear-screen ()
  48.   `(SCREEN:CLEAR-WINDOW *WINDOW*)
  49. )
  50.  
  51. (defmacro screen-clear-end-of-screen ()
  52.   `(SCREEN:CLEAR-WINDOW-TO-EOT *WINDOW*)
  53. )
  54.  
  55. (defmacro screen-clear-end-of-line ()
  56.   `(SCREEN:CLEAR-WINDOW-TO-EOL *WINDOW*)
  57. )
  58.  
  59. (defmacro screen-insert-line ()
  60.   `(SCREEN:INSERT-WINDOW-LINE *WINDOW*)
  61. )
  62.  
  63. (defmacro screen-delete-line ()
  64.   `(SCREEN:DELETE-WINDOW-LINE *WINDOW*)
  65. )
  66.  
  67. (defmacro screen-cursor-on ()
  68.   `(SCREEN:WINDOW-CURSOR-ON *WINDOW*)
  69. )
  70.  
  71. (defmacro screen-cursor-off ()
  72.   `(SCREEN:WINDOW-CURSOR-OFF *WINDOW*)
  73. )
  74.  
  75. (defmacro screen-reverse-on ()
  76.   `(SCREEN:HIGHLIGHT-ON *WINDOW*)
  77. )
  78.  
  79. (defmacro screen-reverse-off ()
  80.   `(SCREEN:HIGHLIGHT-OFF *WINDOW*)
  81. )
  82.  
  83. ;-------------------------------------------------------------------------------
  84.  
  85. ;;; Es werden drei Arten von Koordinaten verwendet:
  86. ;;; (Immer zuerst Zeile, dann Spalte)
  87. ;;;
  88. ;;; (a) Bildschirmkoordinaten
  89. ;;; =========================
  90. ;;;    Sie bezeichnen den Ort auf dem Bildschirm. Der erlaubte Bereich ist
  91. ;;;    [0..global-screen-height[ x [0..global-screen-width[. Dabei ist Zeile 0
  92. ;;;    die oberste Zeile, Spalte 0 die linkeste Spalte.
  93. ;;;
  94. ;;; (b) Fensterkoordinaten
  95. ;;; ======================
  96. ;;;    Sie beziehen sich jeweils auf ein Fenster. Der Ursprung ist dabei die
  97. ;;;    linke obere Ecke des Fensterinneren (d.h. ohne Rahmen). Der erlaubte
  98. ;;;    Bereich ist fⁿr ein Fenster screen im Falle, da▀ es nicht der ganze
  99. ;;;    Bildschirm ist (d.h. screen.full? = nil)
  100. ;;;    [-1..screen.height+1[ x [-1..screen.width+1[, wobei die Randwerte sich
  101. ;;;    auf Orte im Rahmen beziehen. Umfa▀t das Fenster den ganzen Bildschirm,
  102. ;;;    sind die Fensterkoordinaten mit den Bildschirmkoordinaten identisch.
  103. ;;;
  104. ;;; (c) Textkoordinaten
  105. ;;; ===================
  106. ;;;    Sie beziehen sich auf den Text, der in einem Fenster dargestellt wird.
  107. ;;;    Die Zeilenkoordinate lΣuft im Bereich [0..length(screen.text)[, die
  108. ;;;    zur Zeilenkoordineate lin geh÷rige Spaltenkoordinate lΣuft im Bereich
  109. ;;;    [0..length(screen.text[lin])[ (manchmal auch einschlie▀lich der rechten
  110. ;;;    Grenze).
  111. ;;;
  112. ;;; Umrechnung:
  113. ;;; ===========
  114. ;;; (a) -> (b):
  115. ;;;   (lin, col) --> (lin - screen.phys-top-lin, col - screen.phys-left-col)
  116. ;;; (b) -> (c):
  117. ;;;   (lin, col) --> (lin + screen.top-lin, col + screen.left-col)
  118.  
  119. ;-------------------------------------------------------------------------------
  120.  
  121. ;;; Datenstrukturen fⁿr Screens
  122.  
  123. ;; Eine ZEILE ist ein String, adjustable mit Fill-pointer.
  124.  
  125. ;; Liefert neue Zeile der Gr÷▀e >= size und der LΣnge size
  126. (defun get-new-line (size)
  127.   (make-array size
  128.               :element-type 'string-char
  129.               :adjustable t :fill-pointer size
  130. ) )
  131.  
  132. ;; Ein TEXT ist ein Push-Vektor von Zeilen.
  133. (defun make-empty-text (&optional (len global-screen-height))
  134.   (let ((text (make-array len :adjustable t :fill-pointer 0)))
  135.     (vector-push (get-new-line 0) text)
  136.     text
  137. ) )
  138.  
  139. ;; Eine MARKE besteht aus zwei Integers >= 0 (Zeile, Spalte)
  140. (defmacro make-mark (lin col) `(CONS ,lin ,col))
  141. (defmacro mark-lin (mark) `(CAR ,mark))
  142. (defmacro mark-col (mark) `(CDR ,mark))
  143.  
  144. ;; Die Marke (lin,col) hei▀t fⁿr den Text text G▄LTIG, wenn gilt
  145. ;; 0 <= lin < length(text), 0 <= col <= length(text[lin])
  146. ;; (Marken sind immer in Textkoordinaten angegeben.)
  147.  
  148. ;; Ein SCREEN besteht u.a. aus einem Text mit Cursorposition und Marken, sowie
  149. ;; Angaben ⁿber den Fensterausschnitt und die physikalische Lage auf dem Schirm
  150. (defstruct (screen (:copier nil) (:constructor mk-screen))
  151.   (text (make-empty-text))    ; Text des Screens
  152.   (lin 0 :type integer)       ; Cursorzeile
  153.   (col 0 :type integer)       ; Cursorspalte, (lin,col) ist fⁿr den Text gⁿltig
  154.   (saved-col 0 :type integer) ; gemerkte Spalte
  155.   (marks (make-array 12 :adjustable t :fill-pointer 12 :initial-element nil))
  156.     ; Vektor von Marken, die fⁿr den Text gⁿltig sind, oder NIL; LΣnge >= 12.
  157.     ; Die ersten beiden bestimmen den markierten Block.
  158.   (height global-screen-height :type integer) ; H÷he des Bildausschnitts
  159.   (width  global-screen-width  :type integer) ; Breite des Bildausschnitts
  160.   (top-lin  0 :type integer) ; Index der obersten Zeile im Fenster
  161.   (left-col 0 :type integer) ; Index der linkesten Spalte im Fenster
  162.                              ; (Textkoordinaten)
  163.   (visibility nil :type vector) ; Vektor von Listen von Conses: Zu jeder Zeile
  164.                                 ;  die sichtbaren Abschnitte
  165.   (full? t)                  ; Flag, ob ganzer Schirm
  166.   (phys-left-col 0 :type integer) ; physikalische Koordinaten der linken oberen
  167.   (phys-top-lin  0 :type integer) ; Fensterecke (ohne Rahmen)
  168.                                   ; (Bildschirmkoordinaten)
  169.   (title "" :type string)    ; Titel, nur wenn nicht full?
  170.   (olchar nil :type (or null character)) ; obere linke Ecke, nur wenn nicht full?
  171. )
  172.  
  173. ;; Bedingungen:
  174. ;; 0 <= top-lin < length(text)
  175. ;; 0 <= left-col
  176.  
  177. ;; 0 <= phys-left-col
  178. ;; phys-left-col + width <= global-screen-width
  179. ;; 0 <= phys-top-lin
  180. ;; phys-top-lin + height <= global-screen-height
  181. ;; Falls not full?: jeweils < statt <=
  182.  
  183. ;; visibility ist ein Vektor der LΣnge height + 2, EintrΣge sind Listen
  184. ;; ((l_1 . r_1) (l_2 . r_2) ... (l_n . r_n)) mit
  185. ;; -1 <= l_1 < r_1 < l_2 < r_2 < ... < l_n < r_n <= width + 1.
  186. ;; Bedeutung der Liste visibility[i]: Von Zeile i-1 (Zeile -1 ist die
  187. ;; Titelzeile, Zeile height die untere Rahmenzeile, analog fⁿr Spalten
  188. ;; -1, width; das sind Fensterkoordinaten) sind die Abschnitte
  189. ;; [l_1..r_1[, [l_2..r_2[, ..., [l_n..r_n[ sichtbar.
  190.  
  191. ;; make-screen erzeugt einen Screen. Ohne Argumente erhΣlt man einen Screen,
  192. ;; der den ganzen Bildschirm umfa▀t, ansonsten einen mit Rahmen.
  193. (defun make-screen (&key height width left-col top-lin title olchar)
  194.   (if (or height width left-col top-lin title olchar)
  195.     ;; wenigstens ein Argument angegeben
  196.     (let ((min-height 1) (min-width 10))
  197.       (setq height
  198.             (max min-height ; H÷he in den erlaubten Bereich bringen (>= min-height)
  199.               (if height
  200.                 (min height (- global-screen-height 2))
  201.                 ;; Default: Zwei Drittel der Bildschirmh÷he
  202.                 (- (floor (* global-screen-height 0.67s0)) 2)
  203.       )     ) )
  204.       (setq width
  205.             (max min-width ; Breite in den erlaubten Bereich bringen (>= min-width)
  206.               (if width
  207.                 (min width (- global-screen-width 2))
  208.                 ;; Default: Halbe Bildschirmbreite
  209.                 (- (ash global-screen-width -1) 2)
  210.       )     ) )
  211.       (if top-lin
  212.         ;; Oberste Zeile in den erlaubten Bereich bringen und ggfs. H÷he
  213.         ;; anpassen
  214.         (setq top-lin (min (max 1 top-lin) (- global-screen-height min-height 1))
  215.               height (min height (- global-screen-height top-lin 1))
  216.         )
  217.         ;; Default: So, da▀ Fenster in der Mitte sitzt
  218.         (setq top-lin (max 1 (ash (- global-screen-height height) -1)))
  219.       )
  220.       (if left-col
  221.         ;; Linkeste Spalte in den erlaubten Bereich bringen und ggfs. Breite
  222.         ;; anpassen
  223.         (setq left-col (min (max 1 left-col) (- global-screen-width min-width 1))
  224.               width (min width (- global-screen-width left-col 1))
  225.         )
  226.         ;; Default: So, da▀ Fenster in der Mitte sitzt
  227.         (setq left-col (max 1 (ash (- global-screen-width width) -1)))
  228.       )
  229.       (mk-screen :height height :width width :full? nil
  230.                  :title (or title "") :olchar olchar
  231.                  :phys-left-col left-col :phys-top-lin top-lin
  232.                  :text (make-empty-text height)
  233.                  :visibility (make-array (+ height 2) :initial-element '())
  234.     ) )
  235.     (mk-screen :visibility
  236.                (make-array (+ global-screen-height 2) :initial-element '())
  237. ) ) )
  238.  
  239. ;-------------------------------------------------------------------------------
  240.  
  241. ;; Hilfsfunktion: Testet, ob gegebener adjustable Array mit Fillpointer
  242. ;; gro▀ genug ist, und vergr÷▀ert, wenn nicht
  243. ;; Fill-pointer wird auf neue Gr÷▀e gesetzt
  244. (defun resize-array (array size &optional (increment 10))
  245.   (if (>= (array-dimension array 0) size)
  246.     (setf (fill-pointer array) size)
  247.     (adjust-array array (+ size increment) :fill-pointer size)
  248. ) )
  249.  
  250. ;; Hilfsfunktion: verringert den Fill-Pointer eines gegebenen
  251. ;; adjustable Array und l÷scht die dabei wegfallenden Elemente.
  252. (defun shrink-array (array delta)
  253.   (let* ((end (fill-pointer array))
  254.          (start (- end delta)))
  255.     (setf (fill-pointer array) start)
  256.     (when (eq (array-element-type array) 'T)
  257.       (do ((index start (1+ index)))
  258.           ((eql index end))
  259.         (setf (aref array index) nil)
  260. ) ) ) )
  261.  
  262. ;-------------------------------------------------------------------------------
  263.  
  264. ;;; Funktionen fⁿr das Textfenster (intern)
  265.  
  266. ;; Ausgabe eines mit Leerstellen gefⁿllten Zeilenstⁿcks:
  267. (defun display-blanks (left-col right-col)
  268.   ; Auf Terminals sind diese vielen Leerstellen laangsaam...
  269.   (let ((count (- right-col left-col)))
  270.     (if (and (> count 3) (>= right-col global-screen-width))
  271.       (screen-clear-end-of-line)
  272.       (write-string blanks *window* :end count)
  273.   ) )
  274. )
  275.  
  276. ;; Ausgabe einer Zeile:
  277. ;; line:     auszugebende Zeile
  278. ;; mark-start, mark-end:   NIL oder zu markierender Bereich der Zeile
  279. ;; [left-col..right-col[:  darzustellendes Intervall der Zeile
  280. ;; left-arrow?: Flag, ob in der ersten Spalte ein Pfeil nach rechts ausgegeben
  281. ;;              werden soll, wenn dort ein Zeichen stⁿnde
  282. ;; right-arrow? : Analog fⁿr die letzte Spalte
  283. ;; Cursor mu▀ sich an der richtigen Position auf dem Bildschirm befinden,
  284. ;; reverse off, wrap off
  285. ;; right-col - left-col >= [left-arrow?] + [right-arrow?]
  286. (defun display-line (line mark-start mark-end left-col right-col
  287.                      #+DOSE left-arrow? #+DOSE right-arrow?
  288.                     )
  289.   (unless (> (length line) left-col) ; Zeile vorher zu Ende
  290.     (display-blanks left-col right-col)
  291.     (return-from display-line)
  292.   )
  293.   #+DOSE
  294.   (when left-arrow? ; Pfeil nach links ist evtl. auszugeben
  295.     (write-char #+DOSE #\Code17 *window*) ; Pfeil nach links
  296.     (incf left-col) ; jetzt right-col - left-col >= [right-arrow?]
  297.   ) ; hier stets length(line) >= left-col
  298.   (let ((right-col-1 right-col))
  299.     #+DOSE
  300.     (when right-arrow? (decf right-col-1)) ; Pfeil nach rechts ist evtl. auszugeben
  301.     (let ((end-col (min (length line) right-col-1))) ; stets end-col >= left-col
  302.       (cond
  303.         ((or (null mark-start) (null mark-end)
  304.              (<= mark-end left-col) (>= mark-start end-col)
  305.          )
  306.           ;; Zeile ganz au▀erhalb des markierten Bereichs
  307.           (write-string line *window* :start left-col :end end-col)
  308.         )
  309.         ((and (<= mark-start left-col) (<= end-col mark-end))
  310.           ;; Zeile ganz innerhalb des markierten Bereichs: reverse darstellen
  311.           (screen-reverse-on)
  312.           (write-string line *window* :start left-col :end end-col)
  313.           (screen-reverse-off)
  314.         )
  315.         (t ;; sonst: markierten Teil herauspicken und reverse darstellen
  316.            (setq mark-start (max mark-start left-col))
  317.            (setq mark-end (min mark-end end-col))
  318.            (write-string line *window* :start left-col :end mark-start)
  319.            (screen-reverse-on)
  320.            (write-string line *window* :start mark-start :end mark-end)
  321.            (screen-reverse-off)
  322.            (write-string line *window* :start mark-end :end end-col)
  323.       ) )
  324.       (if (eql end-col (length line)) ; Zeile vor dem rechten Rand zu Ende?
  325.         (display-blanks end-col right-col)
  326.         #+DOSE
  327.         (when right-arrow?
  328.           (write-char #+DOSE #\Code16 *window*) ; Pfeil nach rechts
  329.         )
  330. ) ) ) )
  331.  
  332. ;; Ausgabe eines Zeilenstⁿcks:
  333. ;; Zeile lin des screens von Spalte left (einschl.) bis right (ausschl.)
  334. ;; anzeigen (Fensterkoordinaten)
  335. (let ((ohchar #-DOSE #\= #+DOSE #\Code205) ; oberer horizontaler Balken
  336.       (olchar #-DOSE #\# #+DOSE #\Code213) ; obere linke Ecke
  337.       (orchar #-DOSE #\# #+DOSE #\Code184) ; obere rechte Ecke
  338.       (uhchar #-DOSE #\- #+DOSE #\Code196) ; unterer horizontaler Balken
  339.       (ulchar #-DOSE #\+ #+DOSE #\Code192) ; untere linke Ecke
  340.       (urchar #-DOSE #\+ #+DOSE #\Code217) ; untere rechte Ecke
  341.       (lvchar #-DOSE #\| #+DOSE #\Code179) ; linker vertikaler Balken
  342.       (rvchar #-DOSE #\| #+DOSE #\Code179) ; rechter vertikaler Balken
  343.      )
  344.   (defun show-screen-line (screen lin left right)
  345.     (let ((height (screen-height screen)) ; Gr÷▀e und Position des Screens
  346.           (width (screen-width screen))
  347.           (phys-left-col (screen-phys-left-col screen))
  348.           (phys-top-lin (screen-phys-top-lin screen))
  349.          )
  350.       ;; Bereichsⁿberschreitungen abfangen:
  351.       (if (screen-full? screen)
  352.         (setq left (max left 0) right (min right width))
  353.         (setq left (max left -1) right (min right (+ width 1)))
  354.       )
  355.       (when (and (> right left) ; Trifft angegebener Bereich das Fenster?
  356.                  (if (screen-full? screen) (< -1 lin height) (<= -1 lin height))
  357.             )
  358.         ;; Cursor positionieren
  359.         (screen-set-cursor (+ phys-top-lin lin) (+ phys-left-col left))
  360.         (cond
  361.           ((eql lin -1) ; Titelzeile
  362.             (let* ((title (screen-title screen))
  363.                    (tstr (string-concat
  364.                            (string (or (screen-olchar screen) olchar))
  365.                            (if (< (length title) width)
  366.                              (format nil "~V,,0,V:@<~A~>" width ohchar title)
  367.                              (subseq title 0 width)
  368.                            )
  369.                            (string orchar)
  370.                   ))     )
  371.               (write-string tstr *window* :start (1+ left) :end (1+ right))
  372.           ) )
  373.           ((eql lin height) ; untere Rahmenzeile
  374.             (when (eql left -1) (write-char ulchar *window*) (setq left 0))
  375.             (dotimes (i (- (if (eql right (+ width 1)) width right) left))
  376.               (write-char uhchar *window*)
  377.             )
  378.             (when (eql right (+ width 1)) (write-char urchar *window*))
  379.           )
  380.           (t (let* ((text (screen-text screen))
  381.                     (text-lin (+ lin (screen-top-lin screen)))
  382.                     (left-col (screen-left-col screen))
  383.                     (line (if (< text-lin (length text))
  384.                             (aref text text-lin)
  385.                             ""
  386.                     )     )
  387.                     (marks (screen-marks screen))
  388.                     (mark-start (aref marks 0)) ; Blockanfang
  389.                     (mark-end (aref marks 1))   ; Blockende
  390.                    )
  391.                ;; evtl. Stⁿck vom linken Rahmen
  392.                (when (eql left -1) (write-char lvchar *window*) (setq left 0))
  393.                ;; Teil der Zeile ausgeben
  394.                (display-line
  395.                  line
  396.                  ;; Beginn Markierung oder nil
  397.                  (and mark-start
  398.                       (cond ((eql (mark-lin mark-start) text-lin)
  399.                               (mark-col mark-start)
  400.                             )
  401.                             ((< (mark-lin mark-start) text-lin) 0)
  402.                             (t nil)
  403.                  )    )
  404.                  ;; Ende Markierung oder nil
  405.                  (and mark-end
  406.                       (cond ((eql (mark-lin mark-end) text-lin)
  407.                               (mark-col mark-end)
  408.                             )
  409.                             ((> (mark-lin mark-end) text-lin) (length line))
  410.                             (t nil)
  411.                  )    )
  412.                  ;; linke Spalte (Textkoord.)
  413.                  (+ left-col left)
  414.                  ;; rechte Spalte + 1 (Textkoord.)
  415.                  (+ left-col (min right width))
  416.                  ;; Left-Arrow, falls left-col > 0 und erste Fensterspalte
  417.                  ;; dargestellt wird
  418.                  #+DOSE (and (plusp left-col) (eql left 0))
  419.                  ;; Right-Arrow, falls letzte Fensterspalte
  420.                  ;; dargestellt wird
  421.                  #+DOSE (>= right width)
  422.                )
  423.                ;; evtl. Stⁿck vom rechten Rahmen
  424.                (when (eql right (+ width 1)) (write-char rvchar *window*))
  425.   ) ) ) ) )  )
  426. )
  427.  
  428. ;; Ausgabe eines Zeilenstⁿcks:
  429. ;; Zeile lin des screens (im Inneren) von Spalte left (einschl.) bis right
  430. ;; (ausschl.) (Fensterkoordinaten) anzeigen unter Berⁿcksichtigung des
  431. ;; visibility-Vektors.
  432. (defun show-screen-line-v (screen lin left right)
  433.   (let ((height (screen-height screen))
  434.         (width (screen-width screen))
  435.         (visibility (screen-visibility screen))
  436.        )
  437.     ;; Bereichsⁿberschreitungen abfangen:
  438.     (setq left (max left 0) right (min right width))
  439.     (when (and (< left right) (< -1 lin height))
  440.       ;; trifft angegebener Bereich das Fensterinnere?
  441.       ;; Ja: dann die einzelnen Abschnitte abarbeiten
  442.       (dolist (part (aref visibility (1+ lin)))
  443.         (when (and (> (cdr part) left) (< (car part) right))
  444.           (show-screen-line screen lin (max left (car part))
  445.                                        (min right (cdr part))
  446. ) ) ) ) ) )
  447.  
  448. ;; Ausgabe eines Fensters:
  449. ;; screen: Auszugebendes Textfenster
  450. ;; start-lin: Zeile, ab der angezeigt werden soll
  451. ;; end-lin: Zeile, bis vor die angezeigt werden soll (Fensterkoordinaten)
  452. ;; 0 <= start-lin <= end-lin <= screen.height
  453. ;; Liefert screen zurⁿck.
  454. ;; reverse off, wrap off
  455. (defun display-screen (screen &optional (start-lin 0)
  456.                                         (end-lin (screen-height screen))
  457.                       )
  458.   (do ((width (screen-width screen))
  459.        (screen-lin start-lin (1+ screen-lin))
  460.       )
  461.       ((eql screen-lin end-lin) t)
  462.     (show-screen-line-v screen screen-lin 0 width)
  463. ) )
  464.  
  465. ;;; Funktionen zur Verwaltung der visibility-Vektoren
  466.  
  467. ;; Nimm aus einer visibility-Liste das Intervall [left..right[ heraus
  468. (defun update-visibility-list-1 (vl left right)
  469.   ;; Entferne die EintrΣge, die ganz verdeckt werden
  470.   (setq vl (delete-if #'(lambda (pair)
  471.                           (and (<= left (car pair)) (<= (cdr pair) right))
  472.                         )
  473.                       vl
  474.   )        )
  475.   ;; Bestimme die EintrΣge (falls vorhanden), in deren Bereich eine der Grenzen
  476.   ;; fΣllt: diese mⁿssen verkⁿrzt werden
  477.   (let ((left-v (member-if #'(lambda (pair) (< (car pair) left (cdr pair))) vl))
  478.         (right-v (member-if #'(lambda (pair) (< (car pair) right (cdr pair))) vl)))
  479.     ;; (car left-v) und (car right-v) sind zu verkⁿrzen:
  480.     (if (and left-v right-v (eq left-v right-v))
  481.       ;; zu entfernender Bereich innerhalb eines Teilintervalls: in zwei teilen
  482.       ; (... (A . B) ...) --> (... (A . left) (right . B) ...)
  483.       (push (cons right (shiftf (cdr (car left-v)) left)) (cdr left-v))
  484.       (progn
  485.         (when left-v (setf (cdr (car left-v)) left))
  486.         (when right-v (setf (car (car right-v)) right))
  487.   ) ) )
  488.   ;; verΣnderte Liste zurⁿckgeben
  489.   vl
  490. )
  491.  
  492. ;; Fⁿge in eine visibility-Liste das Intervall [left..right[ ein (unter der
  493. ;; Annahme, da▀ es zu den vorhandenen Intervallen disjunkt ist).
  494. (defun update-visibility-list-2 (vl left right)
  495.   (let ((vl1 nil) (vl2 vl))
  496.     (loop ; vl1 und vl2 laufen durch die Liste vl.
  497.           ; Entweder vl1 = nil oder (cdr vl1) = vl2.
  498.           ; Das Intervall [left..right[ ist jedenfalls nach vl1 einzufⁿgen.
  499.       (when (or (null vl2) (<= right (caar vl2))) (return))
  500.       (shiftf vl1 vl2 (cdr vl2))
  501.     )
  502.     ; Das Intervall ist zwischen vl1 und vl2 einzukleben.
  503.     (if (or (null vl2) (< right (caar vl2)))
  504.       (push (cons left right) vl2)
  505.       (setf (caar vl2) left) ; ersetze (caar vl2) = right durch left
  506.     )
  507.     ; Nun ist (caar vl2) = left. vl2 ist an vl1 anzuschlie▀en.
  508.     (if (null vl1)
  509.       (setq vl vl2)
  510.       (if (eql (cdar vl1) left)
  511.         ; (car vl1) und (car vl2) vereinigen:
  512.         (setf (cdar vl1) (cdar vl2) (cdr vl1) (cdr vl2))
  513.         ; vl2 als (cdr vl1) anschlie▀en:
  514.         (setf (cdr vl1) vl2)
  515.   ) ) )
  516.   vl
  517. )
  518.  
  519. ;; Nimm aus dem visibility-Vektor von Screen den Bereich heraus, der durch
  520. ;; [top-lin..bot-lin[ x [left-col..right-col[ (in Bildschirmkoordinaten)
  521. ;; gegeben ist.
  522. (defun update-visibility (screen top-lin bot-lin left-col right-col)
  523.   (let* ((s-top-lin (screen-phys-top-lin screen))
  524.          (s-left-col (screen-phys-left-col screen))
  525.          (visibility (screen-visibility screen))
  526.          ;; Umrechnen auf Fensterkoordinaten
  527.          (rel-top-lin (max -1 (- top-lin s-top-lin)))
  528.          (rel-bot-lin (min (+ (screen-height screen) 1) (- bot-lin s-top-lin)))
  529.          (rel-left-col (max -1 (- left-col s-left-col)))
  530.          (rel-right-col (min (+ (screen-width screen) 1) (- right-col s-left-col)))
  531.         )
  532.     (when (and (> rel-bot-lin rel-top-lin) (> rel-right-col rel-left-col))
  533.       ;; Schnitt ist nicht leer
  534.       (do ((index (1+ rel-top-lin) (1+ index))
  535.            (end-index (1+ rel-bot-lin))
  536.           )
  537.           ((eql index end-index))
  538.         ;; Fⁿr jede Zeile im Schnitt visibility-Liste updaten
  539.         (setf (aref visibility index)
  540.               (update-visibility-list-1 (aref visibility index)
  541.                                         rel-left-col rel-right-col
  542. ) ) ) ) )     )
  543.  
  544. ;; Mache alle Screens der Liste screens im Bereich lin, [left..right[
  545. ;; (Bildschirmkoordinaten) sichtbar, soweit sie sich nicht ⁿberlappen.
  546. ;; (Vorher waren sie dort nicht sichtbar gewesen.)
  547. ;; Die visibility-Listen werden entsprechend aktualisiert.
  548. (defun show-newly-visible-line-parts (screens lin left right)
  549.   (unless (null screens) ; nur etwas zu tun, wenn Screens vorhanden
  550.     (let* ((screen (first screens))
  551.            (screens (rest screens))
  552.            ;; Wir k÷nnen hier davon ausgehen, da▀ jeder Screen einen Rand
  553.            ;; der Breite 1 hat, denn der einzige Screen mit full? = nil
  554.            ;; ist der ganze Bildschirm, und dessen "Rand" wΣre unsichtbar.
  555.            ;; (Es ist ja 0 <= left < right <= global-screen-width und
  556.            ;; und 0 <= lin < global-screen-height.)
  557.            (height (screen-height screen))
  558.            (width+1 (+ (screen-width screen) 1))
  559.            (left-col (screen-phys-left-col screen))
  560.            (visibility (screen-visibility screen))
  561.            ;; Umrechnen auf Fensterkoordinaten
  562.            (rel-lin (- lin (screen-phys-top-lin screen)))
  563.            (rel-left (- left left-col))
  564.            (rel-right (- right left-col))
  565.           )
  566.       (if (and (<= -1 rel-lin height) (<= 0 rel-right) (< rel-left width+1))
  567.         ;; Screen screen ist betroffen
  568.         (progn
  569.           ;; visibility-Liste updaten
  570.           (setf (aref visibility (1+ rel-lin))
  571.                 (update-visibility-list-2 (aref visibility (1+ rel-lin))
  572.                                           (max -1 rel-left)
  573.                                           (min width+1 rel-right)
  574.           )     )
  575.           ;; falls n÷tig, links darunter liegende Screens ansprechen
  576.           (when (< rel-left -1)
  577.             (show-newly-visible-line-parts screens lin left (1- left-col))
  578.           )
  579.           ;; betroffenes Zeilenstⁿck ausgeben
  580.           (show-screen-line screen rel-lin rel-left rel-right)
  581.           ;; falls n÷tig, rechts darunter liegende Screens ansprechen
  582.           (when (> rel-right width+1)
  583.             (show-newly-visible-line-parts screens lin (+ left-col width+1) right)
  584.         ) )
  585.         ;; sonst direkt zu den nΣchsten Screens weitergehen
  586.         (show-newly-visible-line-parts screens lin left right)
  587. ) ) ) )
  588.  
  589. ;-------------------------------------------------------------------------------
  590.  
  591. ;;; Implementierung der Interface-Funktionen
  592.  
  593. ;; Liste der auf dem Bildschirm dargestellten Screens, geordnet nach ihrer
  594. ;; Verdeckungs-Rangfolge (d.h. der oberste zuerst).
  595. (defvar *screens* '())
  596.  
  597. ;; Cursorposition im screen setzen (Textkoordinaten), Wert T.
  598. (defun set-cursor (screen lin &optional (col (screen-saved-col screen) col-s))
  599.   (let* ((text (screen-text screen))
  600.          (text-len (length text)))
  601.     ;; Bereichsⁿberschreitungen abfangen:
  602.     (setq lin (max 0 (min lin (1- text-len))))
  603.     (setq col (max 0 (min col (length (aref text lin)))))
  604.     ;; neue Position vermerken
  605.     (setf (screen-lin screen) lin (screen-col screen) col)
  606.     ;; falls Spalte angegeben, gemerkte Spalte setzen
  607.     (when col-s (setf (screen-saved-col screen) col))
  608.     t
  609. ) )
  610.  
  611. ;; vertikales Scrollen eines Textfensters; upgedateter screen wird zurⁿck-
  612. ;; gegeben
  613. ;; n > 0: n Zeilen nach oben scrollen
  614. ;; n = 0: nichts tun
  615. ;; n < 0: -n Zeilen nach unten scrollen
  616. ;; flag /= nil: Cursor mitverschieben
  617. (defun scroll-vertical (screen n &optional (flag nil))
  618.   (let* ((text (screen-text screen))
  619.          (text-len (length text))
  620.          (top-lin (screen-top-lin screen))
  621.         )
  622.     ;; evtl. Cursor updaten
  623.     (when flag (set-cursor screen (+ (screen-lin screen) n)))
  624.     ;; Bereichsⁿberschreitungen abfangen:
  625.     (setq n (max (- top-lin) (min n (- text-len 1 top-lin))))
  626.     ;; Datenstruktur updaten
  627.     (setf (screen-top-lin screen) (+ top-lin n))
  628.     (when (eql n 0) (return-from scroll-vertical screen))
  629.     (cond ((or (> (abs n) 10)
  630.                (not (screen-full? screen))
  631.                (null *screens*)
  632.                (not (eq screen (first *screens*)))
  633.            )
  634.             ;; n gro▀ oder nicht der ganze Bildschirm oder nicht oberster
  635.             ;; Screen: Fenster neu schreiben
  636.             (display-screen screen)
  637.           )
  638.           ((plusp n) ; nach oben
  639.             (screen-home)
  640.             (dotimes (i n) (screen-delete-line))
  641.             (display-screen screen (- (screen-height screen) n))
  642.           )
  643.           (t ; nach unten
  644.             (screen-home)
  645.             (dotimes (i (- n)) (screen-insert-line))
  646.             (display-screen screen 0 (- n))
  647. ) ) )     )
  648.  
  649. ;; horizontales Scrollen des Textfensters; upgedateter screen zurⁿck
  650. ;; n > 0: um n Spalten nach links scrollen
  651. ;; n = 0: nichts tun
  652. ;; n < 0: um -n Spalten nach rechts scrollen
  653. (defun scroll-horizontal (screen n)
  654.   (let ((left-col (screen-left-col screen)))
  655.     (when (minusp (+ left-col n)) (setq n (- left-col)))
  656.     (if (eql n 0)
  657.       screen
  658.       (progn (setf (screen-left-col screen) (+ left-col n))
  659.              (display-screen screen)
  660. ) ) ) )
  661.  
  662. ;; Cursor setzen und Textfenster ggfs. so verΣndern, da▀ Cursor im Fenster ist,
  663. ;; Cursor einschalten - nur wenn oberster Screen
  664. ;; center: Flag, ob Cursor m÷glichst in der Mitte erscheinen soll
  665. ;; liefert T zurⁿck
  666. (defun set-cursor-visible (screen &optional (center nil))
  667.   (let* ((lin (screen-lin screen))
  668.          (col (screen-col screen))
  669.          (top-lin (screen-top-lin screen))
  670.          (left-col (screen-left-col screen))
  671.          (height (screen-height screen))
  672.          (width (screen-width screen))
  673.         )
  674.     (cond
  675.       ((<= (if (eql left-col 0) 0 (1+ left-col)) col (+ left-col width -2))
  676.         ;; Cursorspalte im Fensterbereich
  677.         (cond
  678.           ((< lin top-lin)
  679.             ;; Cursorzeile ⁿber dem Fenster -> nach unten scrollen
  680.             (scroll-vertical screen
  681.                              (- lin top-lin (if center (ash height -1) 0))
  682.           ) )
  683.           ((>= lin (+ top-lin height))
  684.             ;; Cursorzeile unter dem Fenster -> nach oben scrollen
  685.             (scroll-vertical screen
  686.                         (- lin top-lin -1 (if center (ash height -1) height))
  687.       ) ) ) )
  688.       ((<= top-lin lin (+ top-lin height -1))
  689.         ;; Cursorzeile im Fensterbereich, Cursorspalte aber nicht ->
  690.         ;;  nach rechts oder links scrollen
  691.         (scroll-horizontal screen
  692.             (- col left-col
  693.                (if (or center (< width 40))
  694.                  (ash width -1)
  695.                  (if (<= col left-col) (- width 20) 20)
  696.       ) )   )  )
  697.       ;; sonst: Fensterausschnitt neu setzen
  698.       (t (let ((new-left-col (if (< col (1- width))
  699.                                0
  700.                                (- col (if (or center (< width 40))
  701.                                         (ash width -1)
  702.                                         20
  703.                )             ) )      )
  704.                (new-top-lin (max 0 (- lin (ash height -1))))
  705.               )
  706.            (setf (screen-left-col screen) new-left-col
  707.                  (screen-top-lin screen) new-top-lin
  708.            )
  709.            (display-screen screen)
  710.   ) ) )  )
  711.   (when (and *screens* (eq screen (first *screens*))) ; oberster Screen?
  712.     (screen-set-cursor                    ; Cursor setzen
  713.       (+ (- (screen-lin screen) (screen-top-lin screen))
  714.          (screen-phys-top-lin screen)
  715.       )
  716.       (+ (- (screen-col screen) (screen-left-col screen))
  717.          (screen-phys-left-col screen)
  718.     ) )
  719.     (screen-cursor-on)                    ; und einschalten
  720.   )
  721.   t
  722. )
  723.  
  724. ;; Zeile lin ab Spalte col (Textkoordinaten) auffrischen, Wert T.
  725. (defun refresh-line (screen lin col)
  726.   (show-screen-line-v screen (- lin (screen-top-lin screen))
  727.                              (- col (screen-left-col screen))
  728.                              (screen-width screen)
  729.   )
  730.   t
  731. )
  732.  
  733. ;; Fenster ab Zeile lin bis vor Zeile end-lin (Textkoordinaten) auffrischen,
  734. ;; ab Zeile end-lin um |n| Zeilen scrollen (n>0: nach oben, n<0: nach unten),
  735. ;; Wert T.
  736. (defun refresh-screen (screen lin end-lin &optional (n 0))
  737.   (let ((top-lin (screen-top-lin screen))
  738.         (height (screen-height screen)))
  739.     (when (<= (+ top-lin height) lin)
  740.       ;; Bildschirminhalt kann unverΣndert bleiben
  741.       (return-from refresh-screen t)
  742.     )
  743.     (when (<= end-lin top-lin)
  744.       ;; Bildschirminhalt kann unverΣndert bleiben
  745.       (setf (screen-top-lin screen) (+ top-lin n))
  746.       (return-from refresh-screen t)
  747.     )
  748.     ;; Bildschirminhalt mu▀ teilweise gescrollt werden
  749.     (when (or (> (abs n) 10)
  750.               (not (screen-full? screen))
  751.               (null *screens*)
  752.               (not (eq screen (first *screens*)))
  753.           )
  754.       ;; n gro▀ oder nicht der ganze Bildschirm oder nicht oberster
  755.       ;; Screen: Fenster neu schreiben
  756.       (display-screen screen)
  757.       (return-from refresh-screen t)
  758.     )
  759.     ;; Scrollen
  760.     (cond ((minusp n) ; nach unten
  761.             (setq end-lin (max end-lin (- top-lin n)))
  762.             ; Wir haben  end-lin >= top-lin + |n|  erzwungen.
  763.             (let ((scroll-top (- (+ end-lin n) top-lin))) ; >=0
  764.               (when (< (- scroll-top n) height)
  765.                 (screen-set-cursor scroll-top 0)
  766.                 (dotimes (i (- n)) (screen-insert-line))
  767.           ) ) )
  768.           ((plusp n) ; nach oben
  769.             (let ((scroll-top (- end-lin top-lin))) ; >0
  770.               (when (< scroll-top height)
  771.                 (if (>= (+ scroll-top n) height)
  772.                   (display-screen screen scroll-top height)
  773.                   (progn
  774.                     (screen-set-cursor scroll-top 0)
  775.                     (dotimes (i n) (screen-delete-line))
  776.                     (display-screen screen (- height n) height)
  777.     )     ) ) ) ) )
  778.     ;; Bereich zwischen lin und end-lin anzeigen
  779.     (let ((screen-lin (max 0 (- lin top-lin)))
  780.           (screen-end-lin (min (- end-lin top-lin) height)))
  781.       (when (< screen-lin screen-end-lin)
  782.         (display-screen screen screen-lin screen-end-lin)
  783.   ) ) )
  784.   t
  785. )
  786.  
  787. ;; Fenster vom Bildschirm nehmen, Wert: neuer oberster Screen, falls vorhanden,
  788. ;; sonst NIL
  789. (defun hide-screen (screen)
  790.   (let* ((height+2 (+ (screen-height screen) 2))
  791.          (top-lin (screen-phys-top-lin screen))
  792.          (left-col (screen-phys-left-col screen))
  793.          (visibility (screen-visibility screen))
  794.          ;; screen in *screens* suchen
  795.          (screens (member screen *screens* :test #'eq))
  796.         )
  797.     (when screens ; wenn nicht da, ist nichts zu tun
  798.       (do ((index 0 (1+ index))
  799.            (lin (1- top-lin) (1+ lin))
  800.           )
  801.           ((eql index height+2))
  802.         ;; Zeilen einzeln durchgehen
  803.         (dolist (part (aref visibility index))
  804.           ;; freiwerdende Teile anzeigen
  805.           (show-newly-visible-line-parts
  806.             (rest screens) lin (+ left-col (car part)) (+ left-col (cdr part))
  807.         ) )
  808.         ;; Sichtbarkeit l÷schen
  809.         (setf (aref visibility index) '())
  810.       )
  811.       ;; screen aus den aktiven Screens entfernen
  812.       (setq *screens* (delete screen *screens* :test #'eq))
  813.     )
  814.     (first *screens*)
  815. ) )
  816.  
  817. ;; Fenster nach oben bringen
  818. (defun activate-screen (screen)
  819.   (let* ((height (screen-height screen))
  820.          (width (screen-width screen))
  821.          (top-lin (screen-phys-top-lin screen))
  822.          (left-col (screen-phys-left-col screen))
  823.          (bot-lin (+ top-lin height))
  824.          (right-col (+ left-col width))
  825.          (visibility (screen-visibility screen))
  826.          (left 0)
  827.          (right width)
  828.         )
  829.     (unless (and (not (null *screens*)) (eq screen (first *screens*)))
  830.       ;; falls schon oben, ist nichts zu tun
  831.       (unless (screen-full? screen)
  832.         ;; Rahmen berⁿcksichtigen
  833.         (decf top-lin) (incf bot-lin)
  834.         (decf left-col) (incf right-col)
  835.         (decf left) (incf right)
  836.       )
  837.       ;; [top-lin..bot-lin[ x [left-col..right-col[ ist Screenbereich auf
  838.       ;; dem Bildschirm (in Bildschirmkoordinaten)
  839.       (do ((screens *screens* (rest screens)))
  840.           ((or (null screens) (eq (first screens) screen)))
  841.         ;; visibility updaten fⁿr darⁿber gewesenen Screen
  842.         (update-visibility (first screens) top-lin bot-lin left-col right-col)
  843.       )
  844.       ;; screen in der Liste nach vorne bringen
  845.       (setq *screens* (cons screen (delete screen *screens* :test #'eq)))
  846.       ;; visibility-Listen setzen und Zeilen anzeigen, wenn n÷tig
  847.       (if (screen-full? screen)
  848.         (dotimes (lin height)
  849.           (let ((new-vl (list (cons left right))))
  850.             (unless (equal (aref visibility (1+ lin)) new-vl)
  851.               (setf (aref visibility (1+ lin)) new-vl)
  852.               (show-screen-line screen lin left right)
  853.         ) ) )
  854.         (dotimes (lin (+ height 2))
  855.           (let ((new-vl (list (cons left right))))
  856.             (unless (equal (aref visibility lin) new-vl)
  857.               (setf (aref visibility lin) new-vl)
  858.               (show-screen-line screen (1- lin) left right)
  859.   ) ) ) ) ) )
  860.   t
  861. )
  862.  
  863. ;; Cursor und Marken mitfⁿhren bei Einfⁿge- und L÷schoperationen
  864. (defun update-marks (screen lin1 col1 lin2 col2)
  865.   (flet ((new-lin-col (lin col) ; Berechne neue Koordinaten
  866.            (cond
  867.              ((eql lin1 lin2) ; alles in einer Zeile
  868.                (if (eql lin lin1) ; Σndert sich nur, wenn in dieser Zeile
  869.                  (if (< col1 col)
  870.                    (values lin (+ col (- col2 col1)))
  871.                    (values lin (min col col2))
  872.                  )
  873.                  (values lin col)
  874.              ) )
  875.              ((> lin1 lin2) ; L÷schen eines Textteils ⁿber mehrere Zeilen
  876.                (cond ((eql lin lin2) (values lin (min col col2)))
  877.                      ((eql lin lin1)
  878.                        (values lin2 (max (+ col (- col2 col1)) col2))
  879.                      )
  880.                      ((< lin2 lin lin1) (values lin2 col2))
  881.                      ((< lin1 lin) (values (+ lin (- lin2 lin1)) col))
  882.                      (t (values lin col))
  883.              ) )
  884.              (t (cond ((eql lin lin1) ; Einfⁿgen eines Textteils ⁿber mehrere
  885.                         (if (> col col1) ; Zeilen
  886.                           (values lin2 (+ col (- col2 col1)))
  887.                           (values lin col)
  888.                       ) )
  889.                       ((< lin1 lin) (values (+ lin (- lin2 lin1)) col))
  890.                       (t (values lin col))
  891.         )) ) )  )
  892.     (let ((lin (screen-lin screen))
  893.           (col (screen-col screen))
  894.          )
  895.       ;; Cursor updaten
  896.       (if (and (eql lin lin1) (eql col col1))
  897.         (setf (screen-lin screen) lin2
  898.               (screen-col screen) col2
  899.               (screen-saved-col screen) col2
  900.         )
  901.         (multiple-value-bind (new-lin new-col) (new-lin-col lin col)
  902.           (setf (screen-lin screen) new-lin
  903.                 (screen-col screen) new-col
  904.     ) ) ) )
  905.     (let ((marks (screen-marks screen)))
  906.       ;; Marken updaten
  907.       (dotimes (i (length marks))
  908.         (let ((mark (aref marks i)))
  909.           (when mark
  910.             (multiple-value-bind (new-lin new-col)
  911.                 (new-lin-col (mark-lin mark) (mark-col mark))
  912.               (setf (mark-lin mark) new-lin
  913.                     (mark-col mark) new-col
  914. ) ) ) ) ) ) ) )
  915.  
  916. ;; Screen scrollen um n nach oben, dabei Cursor mitfⁿhren
  917. (defun scroll-screen (screen n)
  918.   (scroll-vertical screen n t)
  919.   t
  920. )
  921.  
  922. ;; mehrere Fenster nacheinander nach oben bringen
  923. ;; sozusagen  (mapc #'activate-screen screen-list)
  924. (defun activate-screens (screen-list)
  925.   (let ((pos (or (position-if #'screen-full? screen-list :from-end t) 0)))
  926.     ; Alle Screens vor pos werden vom Screen bei pos ⁿberdeckt, brauchen
  927.     ; also nicht gezeichnet zu werden.
  928.     (mapc #'activate-screen (nthcdr pos screen-list))
  929. ) )
  930.  
  931. ;###############################################################################
  932. ;;;; Full-Screen-Editor
  933. ;;;;
  934. ;;;; Michael Stoll, Jan./Feb. 1992
  935. ;;;; Bruno Haible 30.3.1992, 13.5.1992
  936.  
  937. (defmacro defun-doc (name lambdalist doc &body body)
  938.   `(PROGN
  939.      (DEFUN ,name ,lambdalist ,@body)
  940.      (SETF (DOCUMENTATION ',name 'FUNCTION) ,doc)
  941.      ',name
  942.    )
  943. )
  944.  
  945. ;===========================================================================
  946. ;  G R U N D F U N K T I O N E N   Z U R   T E X T M A N I P U L A T I O N
  947. ;===========================================================================
  948.  
  949. ;; Liste der bei Undo durchzufⁿhrenden Aktionen:
  950. (defvar *undo* '())
  951.  
  952. #|
  953. ; erstrangige, alles Bisherige ⁿberschattende Undo-Aktion:
  954. (defun undo1 (function)
  955.   (setq *undo* (list function))
  956. )
  957.  
  958. ; zweitrangige, akkumulierende Undo-Aktion:
  959. (defun undo2 (function)
  960.   (push function *undo*)
  961. )
  962.  
  963. ; drittrangige, nur Cursor-bewegende, Undo-Aktion:
  964. (defun undo3 (screen)
  965.   (let ((function
  966.           (let ((lin (screen-lin screen))
  967.                 (col (screen-col screen)))
  968.             #'(lambda () (set-cursor screen lin col))
  969.        )) )
  970.     (undo2 function)
  971. ) )
  972. |# ; vorerst:
  973. (defun undo1 (function) (declare (ignore function)))
  974. (defun undo2 (function) (declare (ignore function)))
  975. (defun undo3 (screen) (declare (ignore screen)))
  976.  
  977. ;-------------------------------------------------------------------------------
  978.  
  979. ;;; Cursor-Bewegung
  980.  
  981. (defun-doc cursor-up (screen)
  982.   (DEUTSCH "Cursor nach oben"
  983.    ENGLISH "cursor up"
  984.    FRANCAIS "curseur vers le haut")
  985.   (let ((lin (screen-lin screen)))
  986.     (and (plusp lin)
  987.          (progn (undo3 screen) (set-cursor screen (1- lin)))
  988. ) ) )
  989.  
  990. (defun-doc cursor-down (screen)
  991.   (DEUTSCH "Cursor nach unten"
  992.    ENGLISH "cursor down"
  993.    FRANCAIS "curseur vers le bas")
  994.   (let ((lin (screen-lin screen)))
  995.     (and (< lin (1- (length (screen-text screen))))
  996.          (progn (undo3 screen) (set-cursor screen (1+ lin)))
  997. ) ) )
  998.  
  999. (defun-doc cursor-left (screen)
  1000.   (DEUTSCH "Cursor nach links"
  1001.    ENGLISH "cursor left"
  1002.    FRANCAIS "curseur α gauche")
  1003.   (let ((lin (screen-lin screen))
  1004.         (col (screen-col screen)))
  1005.     (cond ((plusp col) (decf col))
  1006.           ((plusp lin)
  1007.             (decf lin) (setq col (length (aref (screen-text screen) lin))) )
  1008.           (t (return-from cursor-left nil))
  1009.     )
  1010.     (undo3 screen)
  1011.     (set-cursor screen lin col)
  1012. ) )
  1013.  
  1014. (defun-doc cursor-right (screen)
  1015.   (DEUTSCH "Cursor nach rechts"
  1016.    ENGLISH "cursor right"
  1017.    FRANCAIS "curseur α droite")
  1018.   (let ((text (screen-text screen))
  1019.         (lin (screen-lin screen))
  1020.         (col (screen-col screen)))
  1021.     (cond ((< col (length (aref text lin))) (incf col))
  1022.           ((< lin (1- (length text))) (incf lin) (setq col 0))
  1023.           (t (return-from cursor-right nil))
  1024.     )
  1025.     (undo3 screen)
  1026.     (set-cursor screen lin col)
  1027. ) )
  1028.  
  1029. (defun-doc cursor-to-start-of-line (screen)
  1030.   (DEUTSCH "Cursor an den Zeilenanfang"
  1031.    ENGLISH "cursor to start of line"
  1032.    FRANCAIS "curseur au dΘbut de la ligne")
  1033.   (let ((lin (screen-lin screen)))
  1034.     (undo3 screen)
  1035.     (set-cursor screen lin 0)
  1036. ) )
  1037.  
  1038. (defun-doc cursor-to-end-of-line (screen)
  1039.   (DEUTSCH "Cursor ans Zeilenende"
  1040.    ENGLISH "cursor to end of line"
  1041.    FRANCAIS "curseur α la fin de la ligne")
  1042.   (let ((lin (screen-lin screen)))
  1043.     (undo3 screen)
  1044.     (set-cursor screen lin (length (aref (screen-text screen) lin)))
  1045. ) )
  1046.  
  1047. (defun-doc cursor-to-start-of-text (screen)
  1048.   (DEUTSCH "Cursor an den Textanfang"
  1049.    ENGLISH "cursor to start of text"
  1050.    FRANCAIS "curseur au dΘbut du texte")
  1051.   (undo3 screen)
  1052.   (set-cursor screen 0 0)
  1053. )
  1054.  
  1055. (defun-doc cursor-to-end-of-text (screen)
  1056.   (DEUTSCH "Cursor ans Textende"
  1057.    ENGLISH "cursor to end of text"
  1058.    FRANCAIS "curseur α la fin du texte")
  1059.   (undo3 screen)
  1060.   (let* ((text (screen-text screen))
  1061.          (text-len-1 (1- (length text))))
  1062.     (set-cursor screen text-len-1 (length (aref text text-len-1)))
  1063. ) )
  1064.  
  1065. (defun-doc page-up (screen)
  1066.   (DEUTSCH "Seite nach oben"
  1067.    ENGLISH "page up"
  1068.    FRANCAIS "une page plus haut")
  1069.   (undo3 screen)
  1070.   (scroll-screen screen (- 1 (screen-height screen)))
  1071. )
  1072.  
  1073. (defun-doc page-down (screen)
  1074.   (DEUTSCH "Seite nach unten"
  1075.    ENGLISH "page down"
  1076.    FRANCAIS "une page plus bas")
  1077.   (undo3 screen)
  1078.   (scroll-screen screen (- (screen-height screen) 1))
  1079. )
  1080.  
  1081. (defun-doc line-up (screen)
  1082.   (DEUTSCH "Zeile nach oben"
  1083.    ENGLISH "line up"
  1084.    FRANCAIS "une ligne plus haut")
  1085.   (undo3 screen)
  1086.   (scroll-screen screen -1)
  1087. )
  1088.  
  1089. (defun-doc line-down (screen)
  1090.   (DEUTSCH "Zeile nach unten"
  1091.    ENGLISH "line down"
  1092.    FRANCAIS "une ligne plus bas")
  1093.   (undo3 screen)
  1094.   (scroll-screen screen 1)
  1095. )
  1096.  
  1097. ;-------------------------------------------------------------------------------
  1098.  
  1099. ;; Marken
  1100.  
  1101. (defun set-mark-fn (n)
  1102.   (let ((index (+ n 2)))
  1103.     (labels ((set-mark (screen &optional (lin (screen-lin screen))
  1104.                                          (col (screen-col screen)) )
  1105.                (undo2 (let ((mark-n (aref (screen-marks screen) index)))
  1106.                         (if mark-n
  1107.                           #'(lambda () (setf (aref (screen-marks screen) index) nil))
  1108.                           (let ((old-lin (mark-lin mark-n)) (old-col (mark-col mark-n)))
  1109.                             #'(lambda () (set-mark screen old-lin old-col))
  1110.                )      ) ) )
  1111.                (setf (aref (screen-marks screen) index) (make-mark lin col))
  1112.             ))
  1113.       #'set-mark
  1114. ) ) )
  1115. (defun set-mark-doc (n)
  1116.   (format nil (DEUTSCH "Marke ~D setzen"
  1117.                ENGLISH "set mark ~D"
  1118.                FRANCAIS "placer la marque ~D")
  1119.               n
  1120. ) )
  1121.  
  1122. (defun cursor-to-mark-fn (n)
  1123.   (let ((index (+ n 2)))
  1124.     #'(lambda (screen)
  1125.         (undo3 screen)
  1126.         (let ((mark (aref (screen-marks screen) index)))
  1127.           (and mark (set-cursor screen (mark-lin mark) (mark-col mark)))
  1128.       ) )
  1129. ) )
  1130. (defun cursor-to-mark-doc (n)
  1131.   (format nil (DEUTSCH "Cursor zu Marke ~D"
  1132.                ENGLISH "cursor to mark ~D"
  1133.                FRANCAIS "curseur α la marque ~D")
  1134.               n
  1135. ) )
  1136.  
  1137. ;-------------------------------------------------------------------------------
  1138.  
  1139. ;; Region (start-lin start-col end-lin end-col) = Der Textbereich
  1140. ;; von (make-mark start-lin start-col) bis (make-mark end-lin end-col).
  1141.  
  1142. ;; Eine linelist ist eine umgedrehte nichtleere Liste von Zeilen, die keine
  1143. ;; Newlines enthalten und zwischen denen jeweils ein Newline zu denken ist:
  1144. ;; (stringn ... string0) mit n>=0 steht fⁿr den String
  1145. ;; (string-concat string0 newline-as-string ... newline-as-string stringn).
  1146.  
  1147. (defconstant newline-as-string (string #\Newline))
  1148.  
  1149. ;; Eine Region in eine Liste von Zeilen umwandeln
  1150. (defun region-to-linelist (screen start-lin start-col end-lin end-col)
  1151.   (let ((text (screen-text screen))
  1152.         (linelist '()))
  1153.     (if (eql start-lin end-lin)
  1154.       (push (subseq (aref text start-lin) start-col end-col) linelist)
  1155.       (progn
  1156.         (push (subseq (aref text start-lin) start-col) linelist)
  1157.         (do ((index (1+ start-lin) (1+ index)))
  1158.             ((eql index end-lin))
  1159.           (push (copy-seq (aref text index)) linelist)
  1160.         )
  1161.         (push (subseq (aref text end-lin) 0 end-col) linelist)
  1162.     ) )
  1163.     linelist
  1164. ) )
  1165.  
  1166. ;; String (der Newlines enthalten kann) in Linelist umwandeln:
  1167. (defun string-to-linelist (string)
  1168.   (let ((nlpos (position #\Newline string)))
  1169.     (if (null nlpos)
  1170.       (list string)
  1171.       (macrolet ((subseq (string a b)
  1172.                    `(make-array (- ,b ,a) :element-type 'string-char
  1173.                       :displaced-to ,string :displaced-index-offset ,a
  1174.                     )
  1175.                 ))
  1176.         (let ((linelist (list (subseq string 0 nlpos))))
  1177.           (loop
  1178.             (let ((pos (1+ nlpos)))
  1179.               (when (null (setq nlpos (position #\Newline string :start pos)))
  1180.                 (push (subseq string pos (length string)) linelist)
  1181.                 (return)
  1182.               )
  1183.               (push (subseq string pos nlpos) linelist)
  1184.           ) )
  1185.           linelist
  1186.       ) )
  1187. ) ) )
  1188.  
  1189. ;-------------------------------------------------------------------------------
  1190.  
  1191. ;;; L÷schfunktionen
  1192.  
  1193. ;; delete-char l÷scht das Zeichen unter dem Cursor und liefert T zurⁿck,
  1194. ;; wenn nicht am Zeilenende gewesen und Zeichen gel÷scht, sonst NIL.
  1195. (defun-doc delete-char (screen)
  1196.   (DEUTSCH "Zeichen unter dem Cursor l÷schen"
  1197.    ENGLISH "delete character at cursor"
  1198.    FRANCAIS "effacer le caractΦre sous le curseur")
  1199.   (let* ((text (screen-text screen))
  1200.          (lin (screen-lin screen))
  1201.          (col (screen-col screen))
  1202.          (line (aref text lin))
  1203.          (line-len (length line))
  1204.         )
  1205.     ;; Am Zeilenende?
  1206.     (when (eql col line-len) (return-from delete-char nil))
  1207.     ;; Zeichen l÷schen
  1208.     (undo2 (let ((c (aref line col)))
  1209.              #'(lambda () (insert-char screen c) (cursor-left screen))
  1210.     )      )
  1211.     (replace line line :start1 col :start2 (1+ col))
  1212.     (decf (fill-pointer line))
  1213.     ;; Updaten
  1214.     (update-marks screen lin (1+ col) lin col)
  1215.     (refresh-line screen lin col)
  1216. ) )
  1217.  
  1218. ;; combine-lines vereinigt die Cursorzeile mit der folgenden
  1219. ;; liefert T zurⁿck, wenn Cursorzeile nicht die letzte war, sonst NIL.
  1220. (defun-doc combine-lines (screen)
  1221.   (DEUTSCH "Cursorzeile mit der nΣchsten vereinigen"
  1222.    ENGLISH "combine two lines"
  1223.    FRANCAIS "joindre la ligne du curseur α la suivante")
  1224.   (let* ((text (screen-text screen))
  1225.          (lin (screen-lin screen))
  1226.          (lin+1 (1+ lin))
  1227.          (line (aref text lin))
  1228.          (line-len (length line))
  1229.         )
  1230.     ;; Letzte Zeile?
  1231.     (when (eql lin+1 (length text)) (return-from combine-lines nil))
  1232.     ;; Zeilen zusammenhΣngen
  1233.     (undo2
  1234.       (let ((col (screen-col screen)))
  1235.         #'(lambda ()
  1236.             (set-cursor screen lin line-len)
  1237.             (insert-line screen)
  1238.             (set-cursor screen lin col)
  1239.     ) )   )
  1240.     (let ((second-line (aref text lin+1)))
  1241.       (resize-array line (+ line-len (length second-line)))
  1242.       (replace line second-line :start1 line-len)
  1243.     )
  1244.     ;; Zeilen darunter hinaufschieben
  1245.     (replace text text :start1 lin+1 :start2 (1+ lin+1))
  1246.     (shrink-array text 1)
  1247.     ;; Updaten
  1248.     (update-marks screen lin+1 0 lin line-len)
  1249.     (refresh-screen screen lin lin+1 1)
  1250. ) )
  1251.  
  1252. (defun-doc delete-char-1 (screen)
  1253.   (DEUTSCH "Zeichen unter dem Cursor l÷schen, zeilenⁿbergreifend"
  1254.    ENGLISH "delete character at cursor, across lines"
  1255.    FRANCAIS "effacer le caractΦre sous le curseur, α travers lignes")
  1256.   (or (delete-char screen) (combine-lines screen))
  1257. )
  1258.  
  1259. (defun-doc backspace (screen)
  1260.   (DEUTSCH "Zeichen links vom Cursor l÷schen"
  1261.    ENGLISH "delete character before cursor"
  1262.    FRANCAIS "effacer le caractΦre avant le curseur")
  1263.   (and (plusp (screen-col screen))
  1264.        (cursor-left screen)
  1265.        (delete-char screen)
  1266. ) )
  1267.  
  1268. (defun-doc backspace-1 (screen)
  1269.   (DEUTSCH "Zeichen links vom Cursor l÷schen, zeilenⁿbergreifend"
  1270.    ENGLISH "delete character before cursor, across lines"
  1271.    FRANCAIS "effacer le caractΦre avant le curseur, α travers lignes")
  1272.   (and (cursor-left screen) (delete-char-1 screen))
  1273. )
  1274.  
  1275. ;; Eine Region l÷schen
  1276. (defun delete-region (screen start-lin start-col end-lin end-col)
  1277.   (let ((text (screen-text screen)))
  1278.     (undo3 screen)
  1279.     (undo2
  1280.       (let ((linelist (region-to-linelist screen start-lin start-col end-lin end-col)))
  1281.         #'(lambda ()
  1282.             (set-cursor screen start-lin start-col)
  1283.             (insert-linelist screen linelist)
  1284.     ) )   )
  1285.     (cond
  1286.       ((eql start-lin end-lin) ; innerhalb einer Zeile
  1287.         (let ((line (aref text start-lin)))
  1288.           ;; Stⁿck der Zeile l÷schen
  1289.           (replace line line :start1 start-col :start2 end-col)
  1290.           (decf (fill-pointer line) (- end-col start-col))
  1291.           ;; Updaten
  1292.           (update-marks screen end-lin end-col start-lin start-col)
  1293.           (refresh-line screen start-lin start-col)
  1294.       ) )
  1295.       (t (let* ((line1 (aref text start-lin))
  1296.                 (line2 (aref text end-lin))
  1297.                 (new-size-1 (+ start-col (- (length line2) end-col))))
  1298.            ;; Teile der ersten und letzten Zeile zusammenhΣngen
  1299.            (resize-array line1 new-size-1)
  1300.            (replace line1 line2 :start1 start-col :start2 end-col)
  1301.            ;; Zeilen dazwischen werden frei
  1302.            ;; Zeilen darunter hochschieben
  1303.            (replace text text :start1 (1+ start-lin) :start2 (1+ end-lin))
  1304.            (shrink-array text (- end-lin start-lin))
  1305.            ;; Updaten
  1306.            (update-marks screen end-lin end-col start-lin start-col)
  1307.            (refresh-screen screen start-lin (1+ start-lin) (- end-lin start-lin))
  1308. ) ) ) )  )
  1309.  
  1310. ;; Eine Zeile l÷schen (Zeile, in der der Cursor steht)
  1311. (defun-doc delete-line (screen)
  1312.   (DEUTSCH "Zeile l÷schen"
  1313.    ENGLISH "delete line"
  1314.    FRANCAIS "effacer la ligne")
  1315.   (let* ((text (screen-text screen))
  1316.          (lin (screen-lin screen)))
  1317.     (if (eql lin (1- (length text)))
  1318.       (delete-region screen lin 0 lin (length (aref text lin)))
  1319.       (delete-region screen lin 0 (1+ lin) 0)
  1320. ) ) )
  1321.  
  1322. (defun-doc clear-start-of-line (screen)
  1323.   (DEUTSCH "Vom Zeilenanfang bis Cursorposition l÷schen"
  1324.    ENGLISH "delete part of line left to the cursor"
  1325.    FRANCAIS "effacer la partie de la ligne avant le curseur")
  1326.   (let ((lin (screen-lin screen))
  1327.         (col (screen-col screen)))
  1328.     (delete-region screen lin 0 lin col)
  1329. ) )
  1330.  
  1331. (defun-doc clear-end-of-line (screen)
  1332.   (DEUTSCH "Bis zum Zeilenende l÷schen"
  1333.    ENGLISH "delete up to end of line"
  1334.    FRANCAIS "effacer la partie de la ligne α partir du curseur")
  1335.   (let ((text (screen-text screen))
  1336.         (lin (screen-lin screen))
  1337.         (col (screen-col screen)))
  1338.     (delete-region screen lin col lin (length (aref text lin)))
  1339. ) )
  1340.  
  1341. ;-------------------------------------------------------------------------------
  1342.  
  1343. ;;; Einfⁿgefunktionen
  1344.  
  1345. ;; insert-char fⁿgt an der Cursorpos. ein Zeichen ein, Cursor nach rechts,
  1346. ;; liefert T zurⁿck.
  1347. (defun insert-char (screen char)
  1348.   (let* ((text (screen-text screen))
  1349.          (lin (screen-lin screen))
  1350.          (col (screen-col screen))
  1351.          (line (aref text lin))
  1352.          (line-len (length line)))
  1353.     ;; Zeichen einfⁿgen
  1354.     (undo2 #'(lambda () (backspace screen)))
  1355.     (resize-array line (1+ line-len))
  1356.     (replace line line :start1 (1+ col) :start2 col)
  1357.     (setf (aref line col) char)
  1358.     ;; Updaten
  1359.     (update-marks screen lin col lin (1+ col))
  1360.     (refresh-line screen lin col)
  1361. ) )
  1362.  
  1363. ;; An Cursorpos. einen Zeilenumbruch einfⁿgen und Cursor an den Anfang
  1364. ;; der neuen Zeile setzen
  1365. (defun-doc insert-line (screen)
  1366.   (DEUTSCH "Zeilenumbruch einfⁿgen"
  1367.    ENGLISH "begin new line at cursor"
  1368.    FRANCAIS "casser la ligne en deux")
  1369.   (let* ((text (screen-text screen))
  1370.          (lin (screen-lin screen))
  1371.          (lin+1 (1+ lin))
  1372.          (col (screen-col screen))
  1373.          (line (aref text lin)))
  1374.     ;; Neue Zeile einfⁿgen
  1375.     (undo2 #'(lambda () (backspace-1 screen)))
  1376.     (let ((new-line (get-new-line (- (length line) col))))
  1377.       (replace new-line line :start2 col)
  1378.       (setf (fill-pointer line) col)
  1379.       (resize-array text (1+ (length text)))
  1380.       (replace text text :start1 (1+ lin+1) :start2 lin+1)
  1381.       (setf (aref text lin+1) new-line)
  1382.     )
  1383.     ;; Updaten
  1384.     (update-marks screen lin col lin+1 0)
  1385.     (refresh-screen screen lin (1+ lin+1) -1)
  1386. ) )
  1387.  
  1388. ;; Eine Liste von Zeilen in umgekehrter Reihenfolge an Cursorposition einfⁿgen
  1389. (defun insert-linelist (screen linelist)
  1390.   (let ((text (screen-text screen))
  1391.         (lin (screen-lin screen))
  1392.         (col (screen-col screen)))
  1393.     (cond
  1394.       ((null linelist) t)
  1395.       ((null (rest linelist))
  1396.         ;; kein Zeilenumbruch: String in Zeile einbauen
  1397.         (let* ((line (aref text lin))
  1398.                (piece (first linelist))
  1399.                (piece-len (length piece))
  1400.                (new-col (+ col piece-len)))
  1401.           ;; Zeile um piece-len verlΣngern
  1402.           (resize-array line (+ (length line) piece-len))
  1403.           ;; Platz freimachen
  1404.           (replace line line :start1 new-col :start2 col)
  1405.           ;; und String einkopieren
  1406.           (replace line piece :start1 col)
  1407.           ;; Updaten
  1408.           (update-marks screen lin col lin new-col)
  1409.           (undo2 #'(lambda () (delete-region screen lin col lin new-col)))
  1410.           (refresh-line screen lin col)
  1411.       ) )
  1412.       (t
  1413.         (let* ((nl-count (1- (length linelist)))
  1414.                (last-lin (+ lin nl-count)))
  1415.           ;; Text-Buffer vergr÷▀ern
  1416.           (resize-array text (+ (length text) nl-count))
  1417.           ;; Platz freimachen
  1418.           (replace text text :start1 (1+ last-lin) :start2 (1+ lin))
  1419.           ;; und Zeilen einfⁿgen
  1420.           (let* ((line (aref text lin))
  1421.                  (index last-lin)
  1422.                  (last-line (pop linelist))
  1423.                  (last-len (length last-line)))
  1424.             ;; Letzte neue Zeile mit Rest der Cursorzeile verbinden
  1425.             (let ((new-line (get-new-line (+ last-len (- (length line) col)))))
  1426.               (replace new-line last-line)
  1427.               (replace new-line line :start1 last-len :start2 col)
  1428.               (setf (aref text index) new-line)
  1429.             )
  1430.             ;; Die mittleren Zeilen einfⁿgen
  1431.             (loop
  1432.               (when (null (rest linelist)) (return))
  1433.               (decf index)
  1434.               (let* ((curr-line (pop linelist))
  1435.                      (new-line (get-new-line (length curr-line))))
  1436.                 (replace new-line curr-line)
  1437.                 (setf (aref text index) new-line)
  1438.             ) )
  1439.             ;; Cursorzeilenanfang mit erster einzufⁿgender Zeile kombinieren
  1440.             (let ((first-line (first linelist)))
  1441.               (resize-array line (+ col (length first-line)))
  1442.               (replace line first-line :start1 col)
  1443.             )
  1444.             ;; Updaten
  1445.             (update-marks screen lin col last-lin last-len)
  1446.             (undo2 #'(lambda () (delete-region screen lin col last-lin last-len)))
  1447.             (refresh-screen screen lin (1+ last-lin) (- nl-count))
  1448. ) ) ) ) ) )
  1449.  
  1450. ;; An Cursorpos. einen String einfⁿgen und Cursor an das Ende des eingefⁿgten
  1451. ;; Textes setzen
  1452. (defun insert-string (screen string)
  1453.   (insert-linelist screen (string-to-linelist string))
  1454. )
  1455.  
  1456. ;-------------------------------------------------------------------------------
  1457.  
  1458. ;; Eine Region auf einen Stream schreiben
  1459. (defun write-region (screen start-lin start-col end-lin end-col stream)
  1460.   (let ((text (screen-text screen)))
  1461.     (if (eql start-lin end-lin)
  1462.       (write-string (aref text start-lin) stream :start start-col :end end-col)
  1463.       (progn
  1464.         (write-line (aref text start-lin) stream :start start-col)
  1465.         (do ((index (1+ start-lin) (1+ index)))
  1466.             ((eql index end-lin))
  1467.           (write-line (aref text index) stream)
  1468.         )
  1469.         (write-string (aref text end-lin) stream :end end-col)
  1470.   ) ) )
  1471.   t
  1472. )
  1473.  
  1474. ;; Von einem Stream lesen und einfⁿgen an Cursorposition
  1475. (defun insert-stream (screen stream)
  1476.   (insert-linelist screen
  1477.     (let ((eof "EOF")
  1478.           (linelist '()))
  1479.       (loop
  1480.         (multiple-value-bind (line eof-reached) (read-line stream nil eof)
  1481.           (when (eq line eof) (push "" linelist) (return))
  1482.           (push line linelist)
  1483.           (when eof-reached (return))
  1484.       ) )
  1485.       linelist
  1486. ) ) )
  1487.  
  1488. ;-------------------------------------------------------------------------------
  1489.  
  1490. ;;; Block
  1491.  
  1492. (defun-doc cursor-to-start-of-block (screen)
  1493.   (DEUTSCH "Cursor zum Blockanfang"
  1494.    ENGLISH "cursor to start of block"
  1495.    FRANCAIS "curseur au dΘbut du bloc")
  1496.   (let* ((marks (screen-marks screen))
  1497.          (mark1 (aref marks 0))
  1498.          (mark2 (aref marks 1)))
  1499.     (and mark1 mark2
  1500.          (progn (undo3 screen)
  1501.                 (set-cursor screen (mark-lin mark1) (mark-col mark1))
  1502. ) ) )    )
  1503.  
  1504. (defun-doc cursor-to-end-of-block (screen)
  1505.   (DEUTSCH "Cursor zum Blockende"
  1506.    ENGLISH "cursor to end of block"
  1507.    FRANCAIS "curseur α la fin du bloc")
  1508.   (let* ((marks (screen-marks screen))
  1509.          (mark1 (aref marks 0))
  1510.          (mark2 (aref marks 1)))
  1511.     (and mark1 mark2
  1512.          (progn (undo3 screen)
  1513.                 (set-cursor screen (mark-lin mark2) (mark-col mark2))
  1514. ) ) )    )
  1515.  
  1516. (defun-doc set-block-start (screen &optional (lin (screen-lin screen))
  1517.                                              (col (screen-col screen)) )
  1518.   (DEUTSCH "Blockanfang setzen"
  1519.    ENGLISH "set block start"
  1520.    FRANCAIS "placer le dΘbut du bloc")
  1521.   (undo-blockmarks screen)
  1522.   (let* ((marks (screen-marks screen))
  1523.          (mark1 (aref marks 0))
  1524.          (mark2 (aref marks 1))
  1525.          (end-lin (and mark2 (mark-lin mark2)))
  1526.          (end-col (and mark2 (mark-col mark2)))
  1527.          (start-lin (if mark1 (min (mark-lin mark1) lin) lin)))
  1528.     (unless ; existiert mark2 und liegt hinter (lin,col) ?
  1529.             (and mark2 (or (> end-lin lin)
  1530.                            (and (= end-lin lin) (>= end-col col))
  1531.             )          )
  1532.       (let ((text (screen-text screen)))
  1533.         (setq end-lin (1- (length text)))
  1534.         (setq end-col (length (aref text end-lin)))
  1535.         (setf (aref marks 1) (make-mark end-lin end-col))
  1536.     ) )
  1537.     (setf (aref marks 0) (make-mark lin col))
  1538.     (refresh-screen screen start-lin (1+ end-lin))
  1539. ) )
  1540.  
  1541. (defun-doc set-block-end (screen &optional (lin (screen-lin screen))
  1542.                                            (col (screen-col screen)) )
  1543.   (DEUTSCH "Blockende setzen"
  1544.    ENGLISH "set block end"
  1545.    FRANCAIS "placer la fin du bloc")
  1546.   (undo-blockmarks screen)
  1547.   (let* ((marks (screen-marks screen))
  1548.          (mark1 (aref marks 0))
  1549.          (mark2 (aref marks 1))
  1550.          (start-lin (and mark1 (mark-lin mark1)))
  1551.          (start-col (and mark1 (mark-col mark1)))
  1552.          (end-lin (if mark2 (max (mark-lin mark2) lin) lin)))
  1553.     (unless ; existiert mark1 und liegt vor (lin,col) ?
  1554.             (and mark1 (or (< start-lin lin)
  1555.                            (and (= start-lin lin) (<= start-col col))
  1556.             )          )
  1557.       (setq start-lin 0)
  1558.       (setq start-col 0)
  1559.       (setf (aref marks 0) (make-mark start-lin start-col))
  1560.     )
  1561.     (setf (aref marks 1) (make-mark lin col))
  1562.     (refresh-screen screen start-lin (1+ end-lin))
  1563. ) )
  1564.  
  1565. (defun-doc hide-block (screen)
  1566.   (DEUTSCH "Block demarkieren"
  1567.    ENGLISH "remove block marks"
  1568.    FRANCAIS "enlever les marques du bloc")
  1569.   (undo-blockmarks screen)
  1570.   (let* ((marks (screen-marks screen))
  1571.          (mark1 (aref marks 0))
  1572.          (mark2 (aref marks 1)))
  1573.     (setf (aref marks 0) nil (aref marks 1) nil)
  1574.     (and mark1 mark2
  1575.          (refresh-screen screen (mark-lin mark1) (1+ (mark-lin mark2)))
  1576. ) ) )
  1577.  
  1578. (defun undo-blockmarks (screen)
  1579.   (let* ((marks (screen-marks screen))
  1580.          (mark1 (aref marks 0))
  1581.          (mark2 (aref marks 1)))
  1582.     (when mark2
  1583.       (undo2 (let ((lin (mark-lin mark2)) (col (mark-col mark2)))
  1584.                #'(lambda () (set-block-end screen lin col))
  1585.     ) )      )
  1586.     (when mark1
  1587.       (undo2 (let ((lin (mark-lin mark1)) (col (mark-col mark1)))
  1588.                #'(lambda () (set-block-start screen lin col))
  1589.     ) )      )
  1590.     (undo2 #'(lambda () (hide-block screen)))
  1591. ) )
  1592.  
  1593. (defun mark-region (screen lin1 col1 lin2 col2)
  1594.   (and lin1
  1595.        (let* ((marks (screen-marks screen))
  1596.               (mark1 (aref marks 0))
  1597.               (mark2 (aref marks 1)))
  1598.          (setf (aref marks 0) (make-mark lin1 col1)
  1599.                (aref marks 1) (make-mark lin2 col2)
  1600.          )
  1601.          (when (and mark1 mark2)
  1602.            (setq lin1 (min lin1 (mark-lin mark1))
  1603.                  lin2 (max lin2 (mark-lin mark2))
  1604.          ) )
  1605.          (refresh-screen screen lin1 (1+ lin2))
  1606. ) )    )
  1607.  
  1608. (defun get-block (screen)
  1609.   (let* ((marks (screen-marks screen))
  1610.          (mark1 (aref marks 0))
  1611.          (mark2 (aref marks 1)))
  1612.     (if (and mark1 mark2)
  1613.       (values (mark-lin mark1) (mark-col mark1)
  1614.               (mark-lin mark2) (mark-col mark2)
  1615.       )
  1616.       (values nil nil nil nil)
  1617. ) ) )
  1618.  
  1619. (defun-doc delete-block (screen)
  1620.   (DEUTSCH "Block l÷schen"
  1621.    ENGLISH "delete block"
  1622.    FRANCAIS "effacer le bloc")
  1623.   (let* ((marks (screen-marks screen))
  1624.          (mark1 (aref marks 0))
  1625.          (mark2 (aref marks 1)))
  1626.     (unless (and mark1 mark2) (return-from delete-block nil))
  1627.     (undo-blockmarks screen)
  1628.     (setf (aref marks 0) nil (aref marks 1) nil)
  1629.     (delete-region screen (mark-lin mark1) (mark-col mark1)
  1630.                           (mark-lin mark2) (mark-col mark2)
  1631. ) ) )
  1632.  
  1633. ; Undo ab hier implementieren??
  1634.  
  1635. (defun-doc move-block (screen) ; Block an Cursorposition verschieben
  1636.   (DEUTSCH "Block an Cursorposition verschieben"
  1637.    ENGLISH "move block to cursor position"
  1638.    FRANCAIS "transporter le bloc α la position du curseur")
  1639.   (let* ((marks (screen-marks screen))
  1640.          (mark1 (aref marks 0))
  1641.          (mark2 (aref marks 1)))
  1642.     (unless (and mark1 mark2) (return-from move-block nil))
  1643.     (let* ((lin1 (mark-lin mark1))
  1644.            (col1 (mark-col mark1))
  1645.            (lin2 (mark-lin mark2))
  1646.            (col2 (mark-col mark2))
  1647.            ;; Block in Zeilenliste packen:
  1648.            (linelist (region-to-linelist screen lin1 col1 lin2 col2)))
  1649.       ;; und l÷schen:
  1650.       (delete-region screen lin1 col1 lin2 col2)
  1651.       (let ((lin (screen-lin screen)) ; Cursorpos. merken
  1652.             (col (screen-col screen)))
  1653.         (insert-linelist screen linelist) ; Block an Cursorpos. einfⁿgen
  1654.         (setf (mark-lin mark1) lin    ; alte Cursorpos. = Anfang
  1655.               (mark-col mark1) col
  1656.         )
  1657.         (setf (mark-lin mark2) (screen-lin screen) ; neue Cursorpos. = Ende
  1658.               (mark-col mark2) (screen-col screen)
  1659.         )
  1660.         (refresh-screen screen lin (1+ (screen-lin screen)))
  1661. ) ) ) )
  1662.  
  1663. (defun-doc copy-block (screen) ; Block kopieren (ohne Marken)
  1664.   (DEUTSCH "Block an Cursorposition kopieren"
  1665.    ENGLISH "copy block to cursor position"
  1666.    FRANCAIS "placer une copie du bloc α la position du curseur")
  1667.   (multiple-value-bind (lin1 col1 lin2 col2) (get-block screen)
  1668.     (and lin1
  1669.          (insert-linelist screen
  1670.                           (region-to-linelist screen lin1 col1 lin2 col2)
  1671. ) ) )    )
  1672.  
  1673. ;-------------------------------------------------------------------------------
  1674.  
  1675. ;;; Block und Cut-and-Paste-Buffer
  1676.  
  1677. ;; EnthΣlt umgedrehte Zeilenliste
  1678. (defvar *cut-and-paste-buffer* '())
  1679.  
  1680. (defun-doc copy-block-buffer (screen)
  1681.   (DEUTSCH "Block in Cut-and-Paste-Buffer ⁿbertragen"
  1682.    ENGLISH "copy block into cut-and-paste buffer"
  1683.    FRANCAIS "garder une copie du bloc en mΘmoire")
  1684.   (multiple-value-bind (lin1 col1 lin2 col2) (get-block screen)
  1685.     (and lin1
  1686.          (progn
  1687.            (setq *cut-and-paste-buffer*
  1688.                  (region-to-linelist screen lin1 col1 lin2 col2)
  1689.            )
  1690.            t
  1691. ) ) )    )
  1692.  
  1693. (defun-doc delete-block-buffer (screen)
  1694.   (DEUTSCH "Block l÷schen und in Cut-and-Paste-Buffer ⁿbertragen"
  1695.    ENGLISH "yank block into cut-and-paste buffer"
  1696.    FRANCAIS "effacer le bloc, mais le garder en mΘmoire")
  1697.   (let* ((marks (screen-marks screen))
  1698.          (mark1 (aref marks 0))
  1699.          (mark2 (aref marks 1)))
  1700.     (and mark1 mark2
  1701.          (progn
  1702.            (setf (aref marks 0) nil (aref marks 1) nil)
  1703.            (let ((lin1 (mark-lin mark1))
  1704.                  (col1 (mark-col mark1))
  1705.                  (lin2 (mark-lin mark2))
  1706.                  (col2 (mark-col mark2)))
  1707.              (setq *cut-and-paste-buffer*
  1708.                    (region-to-linelist screen lin1 col1 lin2 col2)
  1709.              )
  1710.              (delete-region screen lin1 col1 lin2 col2)
  1711. ) ) )    ) )
  1712.  
  1713. (defun-doc paste-buffer (screen)
  1714.   (DEUTSCH "Inhalt des Cut-and-Paste-Buffer einfⁿgen"
  1715.    ENGLISH "insert cut-and-paste buffer contents"
  1716.    FRANCAIS "ajouter le bloc en mΘmoire dans le texte")
  1717.   (insert-linelist screen *cut-and-paste-buffer*)
  1718. )
  1719.  
  1720. ;-------------------------------------------------------------------------------
  1721.  
  1722. ;; Macro zum Auswerten von Formen, wobei Fehler abgefangen werden und den Wert
  1723. ;; von errorval liefern
  1724. (defconstant errorval "ERROR")
  1725.  
  1726. (defmacro with-ignored-errors (&body body)
  1727.   (let ((blockvar (gensym)))
  1728.     `(BLOCK ,blockvar
  1729.        (LET ((*ERROR-HANDLER*
  1730.                #'(LAMBDA (&REST ARGS)
  1731.                    (DECLARE (IGNORE ARGS))
  1732.                    (RETURN-FROM ,blockvar ERRORVAL)
  1733.             ))   )
  1734.          ,@body
  1735.      ) )
  1736. ) )
  1737.  
  1738. ;; Dito, mit Ausgabe der Fehlermeldung auf *error-output*
  1739. (defmacro with-trapped-errors (&body body)
  1740.   (let ((blockvar (gensym)))
  1741.     `(BLOCK ,blockvar
  1742.        (LET ((*ERROR-HANDLER*
  1743.                #'(LAMBDA (CONTINUE ERRSTR &REST ARGS)
  1744.                    (DECLARE (IGNORE CONTINUE)) ; vorlΣufig
  1745.                    (FRESH-LINE *ERROR-OUTPUT*)
  1746.                    (APPLY #'FORMAT *ERROR-OUTPUT* ERRSTR ARGS)
  1747.                    (RETURN-FROM ,blockvar ERRORVAL)
  1748.             ))  )
  1749.          ,@body
  1750.      ) )
  1751. ) )
  1752.  
  1753. ;===========================================================================
  1754. ;                        E D I T O R - T O P L E V E L
  1755. ;===========================================================================
  1756.  
  1757. ;; Eine key-table ist eine Hashtable  char -> fun,  die Tastendrⁿcken Prozeduren
  1758. ;; zuordnet. fun ist eine Funktion von einem screen-Argument und gibt einen
  1759. ;; booleschen Wert zurⁿck: t bei Erfolg, nil bei Mi▀erfolg
  1760.  
  1761. ;; Full-Screen-Tabelle
  1762. (defconstant full-table (make-hash-table :test #'eql))
  1763. ;; Read-Only-Tabelle
  1764. (defconstant half-table (make-hash-table :test #'eql))
  1765. ;; Tabelle fⁿr Line-Edit
  1766. (defconstant line-edit-table (make-hash-table :test #'eql))
  1767.  
  1768. ;; Control-Table-Default: Nur Escape
  1769. (defconstant null-table (make-hash-table :test #'eql))
  1770. (setf (gethash #\Escape null-table) '(:LEAVE))
  1771. ;; Volle Control-Table des Editors
  1772. (defconstant control-table (make-hash-table :test #'eql))
  1773.  
  1774. (defconstant docstrings-table (make-hash-table :test #'eql))
  1775.  
  1776. (defun bind-key (keys flag fun &optional (docstring nil))
  1777.   (unless (listp keys) (setq keys (list keys)))
  1778.   (when (and (symbolp fun) (not (null fun)))
  1779.     (unless docstring (setq docstring (documentation fun 'function)))
  1780.     (setq fun (symbol-function fun))
  1781.   )
  1782.   (let ((tables
  1783.           (case flag
  1784.             (:CONTROL (list control-table))
  1785.             (:ALL (list full-table half-table line-edit-table))
  1786.             (:WRITABLE (list full-table line-edit-table))
  1787.             (:MULTILINE (list full-table half-table))
  1788.             (:AND-WRITABLE-MULTILINE (list full-table))
  1789.             (:AND-WRITABLE-NOT-MULTILINE (list line-edit-table))
  1790.        )) )
  1791.     (dolist (key keys)
  1792.       (dolist (table tables)
  1793.         (setf (gethash key table) fun)
  1794.       )
  1795.       (when docstring
  1796.         (setf (gethash key docstrings-table) docstring)
  1797.     ) )
  1798. ) )
  1799.  
  1800. ;; ob der Editor aktiv ist
  1801. (defvar *editor-active* nil)
  1802. ;; wΣhrend der Editor inaktiv ist: letzter Wert von *screens*
  1803. (defvar *saved-screens* '())
  1804. ;; Vektor aller Screens des Editors
  1805. (defvar *edit-screens* (make-array 13 :initial-element nil))
  1806. ;; Vektor dazugeh÷riger Pathnames bzw. Conses (package . env)
  1807. (defvar *screen-paths* (make-array 13 :initial-element nil))
  1808. ;; momentan aktiver Screen
  1809. (defvar *active-screen*)
  1810.  
  1811. ;; Fenster fⁿr Fehlermeldungen
  1812. (defvar error-screen)
  1813. ;; Fenster fⁿr Traces
  1814. (defvar trace-screen)
  1815. ;; Hilfefenster, enthΣlt Tastenzuordnungen
  1816. (defvar help-screen)
  1817. ;; Hauptfenster (ganzer Bildschirm)
  1818. (defvar main-screen)
  1819.  
  1820. ;; Editor
  1821. (defun edit (&optional start-command)
  1822.   (if *editor-active*
  1823.     (throw 'editor-active start-command) ; Editor nicht rekursiv aufrufen!
  1824.     (#-AMIGA with-keyboard
  1825.      #+AMIGA progn
  1826.       (with-window
  1827.         (unless (boundp 'main-screen)
  1828.           (setf (aref *edit-screens* 0)
  1829.             (setf main-screen (make-screen))
  1830.         ) )
  1831.         (unless (boundp 'error-screen)
  1832.           (setf (aref *edit-screens* 10)
  1833.             (setf error-screen
  1834.               (make-screen :title " Errors: " :olchar #\E :height 10 :width 50
  1835.                            :top-lin 2 :left-col (- global-screen-width 53)
  1836.         ) ) ) )
  1837.         (unless (boundp 'trace-screen)
  1838.           (setf (aref *edit-screens* 11)
  1839.             (setf trace-screen
  1840.               (make-screen :title " Trace: " :olchar #\T :height 15 :width 70
  1841.                            :top-lin 8 :left-col 3
  1842.         ) ) ) )
  1843.         (unless (boundp 'help-screen)
  1844.           (setf (aref *edit-screens* 12)
  1845.             (setf help-screen
  1846.               (make-screen :title (DEUTSCH " Tastenzuordnung "
  1847.                                    ENGLISH " Key bindings "
  1848.                                    FRANCAIS " Associations des touches ")
  1849.                            :olchar #\H
  1850.                            :height 15 :width 78
  1851.           ) ) )
  1852.           (insert-linelist help-screen
  1853.             (reverse
  1854.               `(" ==========================================================================="
  1855.                 ,(DEUTSCH "                         T A S T E N B E L E G U N G"
  1856.                   ENGLISH "                           K E Y   B I N D I N G S"
  1857.                   FRANCAIS "               A S S O C I A T I O N S   D E S   T O U C H E S")
  1858.                 " ==========================================================================="
  1859.                 ""
  1860.                 ""
  1861.           ) )  )
  1862.           ;(maphash #'(lambda (key docstring)
  1863.           ;             (insert-string help-screen (format nil "~:@C~25T --> ~A~%" key docstring))
  1864.           ;             (line-up help-screen)
  1865.           ;           )
  1866.           ;         docstrings-table
  1867.           ;)
  1868.           ; Das ist reichlich langsam! Geht's so schneller?
  1869.           (insert-linelist help-screen
  1870.             (reverse
  1871.               (let ((lines '()))
  1872.                 (maphash #'(lambda (key docstring)
  1873.                              (push (format nil "~:@C~25T --> ~A" key (eval docstring)) lines)
  1874.                            )
  1875.                          docstrings-table
  1876.                 )
  1877.                 lines
  1878.           ) ) )
  1879.           (set-cursor help-screen 0 0)
  1880.         )
  1881.         (unless (boundp '*active-screen*)
  1882.           (setf *active-screen* 0)
  1883.         )
  1884.         (unwind-protect
  1885.           (block editor
  1886.             ; Ab hier kann der Editor als aktiv angesehen werden.
  1887.             (activate-screens (cons main-screen *saved-screens*))
  1888.             ; Schleife zum Abfangen und Behandeln der Kommandos:
  1889.             (flet ((handle-command (command &rest args)
  1890.                      (catch 'handle-command
  1891.                        (case command
  1892.                          (:LEAVE (return-from editor))
  1893.                          (:ERROR (setq *active-screen* 10))
  1894.                          (:TRACE (setq *active-screen* 11))
  1895.                          (:HELP (setq *active-screen* 12))
  1896.                          (:TOP
  1897.                            (if (null (aref *edit-screens* (first args)))
  1898.                              (bell)
  1899.                              (setq *active-screen* (first args))
  1900.                          ) )
  1901.                          (:HIDE
  1902.                            (unless args (setq args (list *active-screen*)))
  1903.                            (if (null (aref *edit-screens* (first args)))
  1904.                              (bell)
  1905.                              (let ((new-active
  1906.                                      (hide-screen (aref *edit-screens* (first args)))
  1907.                                   ))
  1908.                                (setq *active-screen*
  1909.                                      (or (and (not (null new-active))
  1910.                                               (position new-active *edit-screens*
  1911.                                                         :test #'eq
  1912.                                          )    )
  1913.                                          0
  1914.                          ) ) ) )     )
  1915.                          (:DELETE
  1916.                            (cond
  1917.                              ((< 0 *active-screen* 10)
  1918.                                (let ((new-active
  1919.                                        (hide-screen (aref *edit-screens* *active-screen*))
  1920.                                     ))
  1921.                                  (setf (aref *edit-screens* *active-screen*) nil)
  1922.                                  (setf (aref *screen-paths* *active-screen*) nil)
  1923.                                  (setq *active-screen*
  1924.                                        (or (and (not (null new-active))
  1925.                                                 (position new-active *edit-screens*
  1926.                                                           :test #'eq
  1927.                                            )    )
  1928.                                            0
  1929.                              ) ) )     )
  1930.                              (t (bell))
  1931.                          ) )
  1932.                          (:SAVE
  1933.                            (unless (aref *screen-paths* *active-screen*)
  1934.                              (setf (aref *screen-paths* *active-screen*) (get-save-path))
  1935.                            )
  1936.                            (let ((screen (aref *edit-screens* *active-screen*))
  1937.                                  (destination (aref *screen-paths* *active-screen*)))
  1938.                              (if (atom destination) ; Pathname oder Cons?
  1939.                                (screen-to-file screen destination)
  1940.                                ; Load vom Screen:
  1941.                                (let ((f (make-read-from-screen-stream screen 0 0))
  1942.                                      (*package* (car destination)) ; *PACKAGE* binden
  1943.                                      (env (cdr destination)) ; Evaluator-Environment
  1944.                                      (end-of-file "EOF")) ; einmaliges Objekt
  1945.                                  (loop
  1946.                                    (let ((obj (read f nil end-of-file)))
  1947.                                      (when (eql obj end-of-file) (return))
  1948.                                      (evalhook obj nil nil env)
  1949.                                ) ) )
  1950.                          ) ) )
  1951.                          (:SAVE-AS
  1952.                            (screen-to-file (aref *edit-screens* *active-screen*) (get-save-path))
  1953.                          )
  1954.                          (:LOAD ; (:LOAD path)
  1955.                            (let ((new-active (position nil *edit-screens*)))
  1956.                              (if (null new-active)
  1957.                                (bell)
  1958.                                (let ((path
  1959.                                        (if args
  1960.                                          (first args)
  1961.                                          (line-edit (DEUTSCH " Lade: "
  1962.                                                      ENGLISH " File to load: "
  1963.                                                      FRANCAIS " Fichier α charger: ")
  1964.                                     )) ) )
  1965.                                  (setq path (with-ignored-errors (pathname path)))
  1966.                                  (if (eq path errorval)
  1967.                                    (bell)
  1968.                                    (progn
  1969.                                      (setf (aref *edit-screens* new-active)
  1970.                                            (file-to-screen path new-active)
  1971.                                      )
  1972.                                      (setf (aref *screen-paths* new-active) path)
  1973.                                      (setq *active-screen* new-active)
  1974.                          ) ) ) ) ) )
  1975.                          (:FORM ; (:FORM sym package env string)
  1976.                            (let ((new-active (position nil *edit-screens*)))
  1977.                              (if (null new-active)
  1978.                                (bell)
  1979.                                (let ((screen (make-screen
  1980.                                                :title (format nil " ~A " (first args))
  1981.                                                :olchar (digit-char new-active)
  1982.                                                :top-lin new-active :width 78 :height 13
  1983.                                     ))       )
  1984.                                  (insert-string screen (fourth args))
  1985.                                  (insert-line screen)
  1986.                                  (set-cursor screen 0 0)
  1987.                                  (setf (aref *edit-screens* new-active) screen)
  1988.                                  (setf (aref *screen-paths* new-active) (cons (second args) (third args)))
  1989.                                  (setq *active-screen* new-active)
  1990.                          ) ) ) )
  1991.                          (t (bell))
  1992.                   )) ) )
  1993.               (loop
  1994.                 (setq start-command
  1995.                   (catch 'editor-active
  1996.                     (let ((*editor-active* t))
  1997.                       ; nΣchstes Kommando holen und abarbeiten:
  1998.                       (apply #'handle-command
  1999.                         (or start-command
  2000.                             (edit1 (aref *edit-screens* *active-screen*)
  2001.                                    control-table
  2002.                                    (if (< *active-screen* 10) full-table half-table)
  2003.                       ) )   )
  2004.                       nil
  2005.               ) ) ) )
  2006.           ) )
  2007.           (setq *saved-screens* (nreverse (copy-list *screens*)))
  2008.           (doseq (screen *edit-screens*)
  2009.             (unless (null screen) (hide-screen screen))
  2010.           )
  2011.           (screen-clear-screen)
  2012. ) ) ) ) )
  2013.  
  2014. #|
  2015. ;; Editierfunktion: Editiere ein Fenster
  2016. (defun edit-screen (screen &optional (key-table-1 null-table)
  2017.                                      (key-table-2 full-table)
  2018.                    )
  2019.   (edit1 screen key-table-1 key-table-2)
  2020. )
  2021. |#
  2022.  
  2023. ;; Defaultfunktion fⁿr Tastenzuordnung: Nichts tun, Mi▀erfolg melden (= NIL)
  2024. (defun return-nil (&rest args)
  2025.   (declare (ignore args))
  2026.   nil
  2027. )
  2028.  
  2029. ;; Editier-Hauptschleife
  2030. (defun edit1 (screen key-table-1 key-table-2)
  2031.   (activate-screen screen)
  2032.   (catch 'edit
  2033.     (flet ((read-edit-command ()
  2034.              (prog2
  2035.                (set-cursor-visible screen) ; Cursor ins Fenster und einschalten
  2036.                (screen:read-keyboard-char *window*)
  2037.                (screen-cursor-off) ; Cursor abschalten
  2038.            ) )
  2039.            (execute-edit-command (char)
  2040.              (catch 'handle-command
  2041.                (if (and (string-char-p char)
  2042.                         (char>= char #\Space)
  2043.                         (not (char= char #\Rubout))
  2044.                    )
  2045.                  ;; normales Zeichen: unter Key :string-char nachschauen
  2046.                  (or (funcall (gethash :string-char key-table-2 #'return-nil)
  2047.                               screen char
  2048.                      )
  2049.                      (bell)
  2050.                  )
  2051.                  ;; sonst: erst Bedeutung fⁿr Editier-Ende nachsehen
  2052.                  (multiple-value-bind (return-value presentp)
  2053.                      (gethash char key-table-1)
  2054.                    (when presentp (throw 'edit return-value))
  2055.                    ;; sonst Editierfunktion ausfⁿhren
  2056.                    (or (funcall (gethash char key-table-2 #'return-nil) screen)
  2057.                        (bell) ; falls undefiniert oder ohne Erfolg
  2058.           )) ) ) ) )
  2059.       (loop (execute-edit-command (read-edit-command)))
  2060. ) ) )
  2061.  
  2062. ;; Einen Pfad fⁿrs Abspeichern erfragen
  2063. (defun get-save-path ()
  2064.   (let (path)
  2065.     (loop
  2066.       (setq path (line-edit (DEUTSCH " Abspeichern als: "
  2067.                              ENGLISH " Save as: "
  2068.                              FRANCAIS " Garder sous le nom: ")
  2069.       )          )
  2070.       (setq path (with-ignored-errors (pathname path)))
  2071.       (unless (eq path errorval) (return))
  2072.       (bell)
  2073.     )
  2074.     path
  2075. ) )
  2076.  
  2077. ;; Eine Zeile editieren und Ergebnis zurⁿckliefern
  2078. (defun line-edit (title &optional (old ""))
  2079.   (let ((query-screen (make-screen :height 1 :width 40 :title title)))
  2080.     (insert-string query-screen old)
  2081.     (let ((command
  2082.             (edit1 query-screen null-table line-edit-table)
  2083.          ))
  2084.       (hide-screen query-screen)
  2085.       (when (eq (first command) ':LEAVE) ; bei Escape
  2086.         (throw 'handle-command nil) ; aktuelles Kommando abbrechen
  2087.       )
  2088.       (copy-seq (aref (screen-text query-screen) 0))
  2089. ) ) )
  2090.  
  2091. ;===========================================================================
  2092. ;                      A R B E I T E N   M I T   F I L E S
  2093. ;===========================================================================
  2094.  
  2095. ;; Ein File in einen Screen einlesen, leerer Screen, falls File nicht vorhanden
  2096. (defun file-to-screen (path number) ; 1 <= number <= 9
  2097.   (let ((screen (make-screen
  2098.                   :title (format nil " ~A " (enough-namestring path))
  2099.                   :olchar (digit-char number)
  2100.                   :top-lin number :width 78 :height 13
  2101.        ))       )
  2102.     (when (probe-file path)
  2103.       (with-open-file (s path :direction :input) (insert-stream screen s))
  2104.       (set-cursor screen 0 0)
  2105.     )
  2106.     screen
  2107. ) )
  2108.  
  2109. ;; Screen in ein File schreiben
  2110. (defun screen-to-file (screen file)
  2111.   (let* ((text (screen-text screen))
  2112.          (text-len-1 (1- (length text)))
  2113.         )
  2114.     (with-open-file (s file :direction :output :if-exists :rename)
  2115.       (write-region screen 0 0 text-len-1 (length (aref text text-len-1)) s)
  2116.   ) )
  2117.   t
  2118. )
  2119.  
  2120. ;===========================================================================
  2121. ;  E I N Z E L F U N K T I O N E N   F ▄ R   T A S T E N Z U O R D N U N G
  2122. ;===========================================================================
  2123.  
  2124. (defun finish (screen)
  2125.   (declare (ignore screen))
  2126.   (throw 'edit '(:FINISH))
  2127. )
  2128.  
  2129. ;; Erzeuge einen Stream, der aus dem screen ab Position lin1,col1 bis Position
  2130. ;; lin2,col2 (optional, Default Textende) liest;
  2131. ;; Zweiter Wert ist eine Funktion von 0 Argumenten, die die Position, bis zu
  2132. ;; der gelesen wurde, angibt (als (values lin col)).
  2133. ;; Solange der Stream verwendet wird, sollten Modifikationen des screen
  2134. ;; unterbleiben.
  2135. (defun make-read-from-screen-stream (screen lin1 col1 &optional lin2 col2)
  2136.   (let ((text (screen-text screen)))
  2137.     (unless lin2 (setq lin2 (1- (length text))))
  2138.     (unless col2 (setq col2 (length (aref text lin2))))
  2139.     ; Region von (lin1,col1) bis (lin2,col2) lesen:
  2140.     (let* ((lastlin nil)
  2141.            (lastcol nil)
  2142.            (stream
  2143.              (make-buffered-input-stream
  2144.                ; Funktion, die abwechselnd ein Textstⁿck und ein Newline
  2145.                ; durchreicht, bis die Region zu Ende ist:
  2146.                #'(lambda ()
  2147.                    ; lin1, col1 laufen.
  2148.                    (if (or (> lin1 lin2) (and (= lin1 lin2) (>= col1 col2)))
  2149.                      nil ; Ende der Region
  2150.                      (let ((line (aref text lin1)))
  2151.                        (setq lastlin lin1 lastcol col1)
  2152.                        (if (>= col1 (length line)) ; am Zeilenende?
  2153.                          ; Zeilenende: Newline durchreichen
  2154.                          (progn
  2155.                            (incf lin1) (setq col1 0)
  2156.                            (values newline-as-string 0 1)
  2157.                          )
  2158.                          ; sonst: Zeile bzw. Zeilenrest durchreichen
  2159.                          (values line col1 (setq col1 (length line)))
  2160.                  ) ) ) )
  2161.                nil
  2162.           )) )
  2163.       (values
  2164.         stream
  2165.         ; Funktion, die die Position im Screen liefert, an der der Stream
  2166.         ; sich gerade befindet:
  2167.         ; Stream hat einen String und einen internen Index.
  2168.         ; Zustand 1 (sofort nach Initialisierung):
  2169.         ;           String = "", Index = 0, liefere (lin1,col1).
  2170.         ; Zustand 2 (nach Zeilen-▄bergabe):
  2171.         ;           String = Zeile, lastcol <= index <= col1, lastlin = lin1,
  2172.         ;           liefere (lin1,index).
  2173.         ; Zustand 3 (nach Newline-▄bergabe):
  2174.         ;           String = Newline-as-String, col1 = 0,
  2175.         ;           bei Index = 0 liefere (lastlin,lastcol),
  2176.         ;           bei Index = 1 liefere (lin1,col1).
  2177.         #'(lambda ()
  2178.             (let ((index (sys::buffered-input-stream-index stream)))
  2179.               (if (eql index 0)
  2180.                 ; Zustand 1 oder 2 oder 3a
  2181.                 (values lastlin lastcol)
  2182.                 ; Zustand 2 oder 3b
  2183.                 (values lin1 (min index col1))
  2184.           ) ) )
  2185.       )
  2186. ) ) )
  2187.  
  2188. ;; Erzeuge einen Stream, der ab Cursorposition in den screen schreibt
  2189. (defun make-write-to-screen-stream (screen)
  2190.   (make-buffered-output-stream
  2191.     #'(lambda (string) (insert-string screen string))
  2192.     (screen-col screen)
  2193. ) )
  2194.  
  2195. ;; Erzeuge einen Stream, der ab Textende in den screen schreibt und ein
  2196. ;; Flag setzt, wenn etwas geschrieben wurde
  2197. (defmacro make-write-to-screen-stream-with-flag (screenform flagvar)
  2198.   (let ((stringvar (gensym)) (screenvar (gensym)))
  2199.     `(LET ((,screenvar ,screenform))
  2200.        (CURSOR-TO-END-OF-TEXT ,screenvar)
  2201.        (MAKE-BUFFERED-OUTPUT-STREAM
  2202.          #'(LAMBDA (,stringvar)
  2203.              (INSERT-STRING ,screenvar ,stringvar)
  2204.              (WHEN (PLUSP (LENGTH ,stringvar)) (SETQ ,flagvar T))
  2205.            )
  2206.          (SCREEN-COL ,screenvar)
  2207. ) )  ) )
  2208.  
  2209. ;; Lies ein Objekt aus dem angegebenen Bereich, werte es aus und schreibe das
  2210. ;; Ergebnis in den Haupt-Text.
  2211. ;; VorlΣufige Version: Keine Umleitung von *query-io* und *debug-io* auf
  2212. ;; Fenster.
  2213. (defun eval-region (screen lin1 col1 lin2 col2)
  2214.   (unless lin1 (return-from eval-region nil))
  2215.   (let* ((errorflag nil)
  2216.          (traceflag nil)
  2217.          (instream (make-read-from-screen-stream screen lin1 col1 lin2 col2))
  2218.          (*standard-output* (make-write-to-screen-stream main-screen))
  2219.          (*error-output*
  2220.            (make-write-to-screen-stream-with-flag error-screen errorflag))
  2221.          (*trace-output*
  2222.            (make-write-to-screen-stream-with-flag trace-screen traceflag))
  2223.          (results
  2224.            (multiple-value-list (with-trapped-errors (eval (read instream))))
  2225.         ))
  2226.     (close instream)
  2227.     ;; Werte dazu
  2228.     (unless (or (null results) errorflag)
  2229.       (fresh-line)
  2230.       (loop
  2231.         (prin1 (pop results))
  2232.         (when (null results) (return))
  2233.         (write-char #\Space) (write-char #\;) (terpri)
  2234.     ) )
  2235.     (fresh-line)
  2236.     (close *standard-output*)
  2237.     (close *error-output*)
  2238.     (close *trace-output*)
  2239.     (when errorflag (throw 'edit '(:ERROR)))
  2240.     (when traceflag (throw 'edit '(:TRACE)))
  2241.     t
  2242. ) )
  2243.  
  2244. ;; Lies ein Objekt aus dem Block, werte es aus und schreibe das Ergebnis
  2245. ;; in den Text.
  2246. (defun-doc eval-block (screen)
  2247.   (DEUTSCH "Block-Inhalt auswerten"
  2248.    ENGLISH "evaluate block contents"
  2249.    FRANCAIS "Θvaluer le contenu du bloc")
  2250.   (multiple-value-call #'eval-region screen (get-block screen))
  2251. )
  2252.  
  2253. (defun get-whitespace-right (screen &optional (lin (screen-lin screen))
  2254.                                               (col (screen-col screen)) )
  2255.   (let* ((text (screen-text screen))
  2256.          (text-len-1 (1- (length text)))
  2257.          (line (aref text lin)))
  2258.     (loop
  2259.       (let ((col1 (position #\Space line :start col :test-not #'eql)))
  2260.         (when col1 (return (values lin col1)))
  2261.       )
  2262.       (when (eql lin text-len-1) (return nil))
  2263.       (incf lin)
  2264.       (setq col 0)
  2265.       (setq line (aref text lin))
  2266. ) ) )
  2267.  
  2268. (defun-doc skip-whitespace-right (screen)
  2269.   (DEUTSCH "Whitespace nach rechts ⁿberspringen"
  2270.    ENGLISH "skip whitespace right"
  2271.    FRANCAIS "sauter le blanc α droite")
  2272.   (multiple-value-bind (lin col) (get-whitespace-right screen)
  2273.     (and lin
  2274.          (set-cursor screen lin col)
  2275. ) ) )
  2276.  
  2277. ; Eine Kopie der Readtable *readtable*, modifiziert fⁿr den Syntaxcheck.
  2278. (defun modified-readtable ()
  2279.   (let ((readtable (copy-readtable)))
  2280.     (set-macro-character #\|
  2281.       #'(lambda (stream char)
  2282.           (declare (ignore char))
  2283.           (when (eql (peek-char nil stream nil) #\#)
  2284.             (sys::error-of-type 'stream-error
  2285.               :stream stream
  2286.               (DEUTSCH "~S von ~S: |# ist nur nach #| zulΣssig."
  2287.                ENGLISH "~S from ~S: |# is legal only after #|"
  2288.                FRANCAIS "~S de ~S : |# est permis qu'aprΦs #|")
  2289.               'read stream
  2290.         ) ) )
  2291.       nil ; terminating macro character
  2292.       readtable
  2293.     )
  2294.     readtable
  2295. ) )
  2296.  
  2297. (defun get-next-object (screen &optional (old-lin (screen-lin screen))
  2298.                                          (old-col (screen-col screen))
  2299.                                          (readtable (modified-readtable)) )
  2300.   (multiple-value-bind (lin col) (get-whitespace-right screen old-lin old-col)
  2301.     (if lin
  2302.       (multiple-value-bind (instream get-end-pos)
  2303.           (make-read-from-screen-stream screen lin col)
  2304.         (unwind-protect
  2305.           (if (eq (with-ignored-errors ; Errors abfangen
  2306.                     (let ((*read-suppress* t) ; nur Syntaxcheck
  2307.                           (sys::*backquote-level* most-positive-fixnum) ; Bei Komma kein Error!
  2308.                           (*readtable* readtable)) ; |# soll Error liefern
  2309.                       (read-preserving-whitespace instream t nil t)
  2310.                   ) )
  2311.                   errorval
  2312.               )
  2313.             (values nil nil nil nil)
  2314.             (multiple-value-call #'values lin col (funcall get-end-pos))
  2315.           )
  2316.           (close instream)
  2317.       ) )
  2318.       (values nil nil nil nil)
  2319. ) ) )
  2320.  
  2321. (defun-doc mark-next-object (screen)
  2322.   (DEUTSCH "NΣchstes LISP-Objekt markieren"
  2323.    ENGLISH "mark next Lisp object"
  2324.    FRANCAIS "marquer le prochain objet Lisp")
  2325.   (multiple-value-call #'mark-region screen (get-next-object screen))
  2326. )
  2327.  
  2328. (defun get-toplevel-form (screen)
  2329.   (let ((text (screen-text screen))
  2330.         (lin (screen-lin screen))
  2331.         (col (screen-col screen)))
  2332.     ;; Klettere Zeilen hoch. Zeilen, die (nach evtl. Spaces) mit Semikolon
  2333.     ;; oder Klammer zu beginnen, werden ignoriert. Zeilen, deren Einrⁿcktiefe
  2334.     ;; gr÷▀er als eine weiter unten angetroffene ist, werden ebenfalls
  2335.     ;; ignoriert. Passiert eine Zeile diese Kriterien, wird versucht, ab ihr
  2336.     ;; zu lesen, und zwischen dem Ende der dabei erkannten Form und der
  2337.     ;; aktuellen Position darf nur Whitespace vorkommen.
  2338.     ; 1. Schritt: Whitespace nach links ⁿbergehen:
  2339.     (let ((line (aref text lin)))
  2340.       (loop
  2341.         (let ((col1 (position #\Space line :end col :test-not #'eql :from-end t)))
  2342.           (when col1 ; Non-Space gefunden, col verkleinern
  2343.             (setq col (1+ col1))
  2344.             (return)
  2345.           )
  2346.           ; Keines gefunden, probiere Zeile davor:
  2347.           (when (eql lin 0) (setq col 0) (return))
  2348.           (decf lin)
  2349.           (setq line (aref text lin))
  2350.           (setq col (length line))
  2351.     ) ) )
  2352.     ; 2. Schritt: Hochklettern:
  2353.     (let ((readtable (modified-readtable)) ; modifizierte Readtable pre-allozieren
  2354.           (lin1 lin)
  2355.           (older-marks '())
  2356.           (older-indent most-positive-fixnum))
  2357.       (loop
  2358.         (let* ((line (aref text lin1))
  2359.                (indent (position #\Space line :test-not #'eql)))
  2360.           (when (and indent
  2361.                      (not (member (char line indent) '( #\; #\) ))) ; (
  2362.                      (<= indent older-indent)
  2363.                 )
  2364.             (setq older-indent indent)
  2365.             (multiple-value-bind (lin0 col0 lin2 col2)
  2366.                 (get-next-object screen lin1 indent readtable)
  2367.               (when lin0
  2368.                 ; Ein Objekt geht von (lin0,col0) bis (lin2,col2).
  2369.                 (when (or (< lin0 lin)
  2370.                           (and (= lin0 lin) (<= col0 col))
  2371.                       )
  2372.                   ; Es fΣngt vor (lin,col) an.
  2373.                   (when (or (< lin lin2)
  2374.                             (and (= lin lin2) (<= col col2))
  2375.                         )
  2376.                     ; Es h÷rt hinter (lin,col) auf.
  2377.                     (push (list lin0 col0 lin2 col2) older-marks)
  2378.         ) ) ) ) ) )
  2379.         (when (eql lin1 0) (return))
  2380.         (decf lin1)
  2381.       )
  2382.       ; Wenn passende Objekte gefunden wurden, dann liefere den Σu▀ersten:
  2383.       (if older-marks
  2384.         (values-list (first older-marks))
  2385.         (values nil nil nil nil)
  2386.       )
  2387. ) ) )
  2388.  
  2389. (defun-doc mark-toplevel-form (screen)
  2390.   (DEUTSCH "Toplevel-Form markieren"
  2391.    ENGLISH "mark surrounding top level form"
  2392.    FRANCAIS "marquer la forme entourante extΘrieure")
  2393.   (multiple-value-call #'mark-region screen (get-toplevel-form screen))
  2394. )
  2395.  
  2396. (defun-doc eval-toplevel-form (screen)
  2397.   (DEUTSCH "Toplevel-Form auswerten"
  2398.    ENGLISH "evaluate surrounding top level form"
  2399.    FRANCAIS "Θvaluer la forme entourante extΘrieure")
  2400.   (multiple-value-call #'eval-region screen (get-toplevel-form screen))
  2401. )
  2402.  
  2403. (defun get-next-tab-pos (screen lin col)
  2404.   (let* ((text (screen-text screen))
  2405.          (line (aref text lin))
  2406.          (line-len (length line))
  2407.         )
  2408.     (cond ((>= col line-len) line-len)
  2409.           ((eql (char line col) #\Space)
  2410.             (or (position #\Space line :start col :test-not #'eql) line-len)
  2411.           )
  2412.           ((eql (char line col) #\( ) ; )
  2413.             (min (+ col 2) line-len)
  2414.           )
  2415.           (t (let ((col1 (position #\Space line :start col)))
  2416.                (if col1
  2417.                  (or (position #\Space line :start col1 :test-not #'eql)
  2418.                      line-len
  2419.                  )
  2420.                  line-len
  2421. ) ) )     )  ) )
  2422.  
  2423. (defun cursor-to-col (screen col)
  2424.   (let* ((text (screen-text screen))
  2425.          (lin (screen-lin screen))
  2426.          (line (aref text lin))
  2427.          (line-len (length line))
  2428.         )
  2429.     (when (> col line-len)
  2430.       (resize-array line col)
  2431.       (fill line #\Space :start line-len)
  2432.       (refresh-line screen lin line-len)
  2433.     )
  2434.     (set-cursor screen lin col)
  2435. ) )
  2436.  
  2437. (defun-doc next-indent (screen)
  2438.   (DEUTSCH "Leerstellen bis zur nΣchsten Einrⁿckung"
  2439.    ENGLISH "insert spaces up to next tab stop"
  2440.    FRANCAIS "ajouter des espaces jusqu'au prochain tabulateur")
  2441.   (let ((lin (screen-lin screen))
  2442.         (col (screen-col screen)))
  2443.     (if (eql lin 0)
  2444.       (cursor-to-col screen (+ col 2))
  2445.       (cursor-to-col screen (get-next-tab-pos screen (1- lin) col))
  2446. ) ) )
  2447.  
  2448. (defvar *search-string* "") ; String, nach dem gesucht werden soll
  2449.  
  2450. (defun-doc search-first (screen)
  2451.   (DEUTSCH "Nach Textstⁿck Suchen"
  2452.    ENGLISH "search for a string"
  2453.    FRANCAIS "chercher une chaεne")
  2454.   (setq *search-string*
  2455.     (line-edit (DEUTSCH " Suche: "
  2456.                 ENGLISH " Search: "
  2457.                 FRANCAIS " Chercher: ")
  2458.                *search-string*
  2459.   ) )
  2460.   (search-next screen)
  2461. )
  2462.  
  2463. (defun-doc search-next (screen)
  2464.   (DEUTSCH "Weitersuchen"
  2465.    ENGLISH "continue searching"
  2466.    FRANCAIS "continuer α chercher")
  2467.   (let* ((text (screen-text screen))
  2468.          (lin (screen-lin screen))
  2469.          (col (screen-col screen))
  2470.          (text-len (length text))
  2471.          (index (if (< col (length (aref text lin)))
  2472.                   (search *search-string* (aref text lin) :start2 (1+ col))
  2473.                   nil
  2474.         ))      )
  2475.     (if index
  2476.       (set-cursor screen lin index)
  2477.       (loop (when (eql (incf lin) text-len) (return nil))
  2478.             (setq index (search *search-string* (aref text lin)))
  2479.             (when index (return (set-cursor screen lin index)))
  2480. ) ) ) )
  2481.  
  2482. ;===========================================================================
  2483. ;                        T A S T E N B E L E G U N G
  2484. ;===========================================================================
  2485.  
  2486. ;; Brunos Tastenbelegung:
  2487.  
  2488. #+DOSE
  2489. (progn
  2490.  
  2491. (defun C-H-doc (n)
  2492.   (format nil (DEUTSCH "Fenster Nr. ~D nach oben bringen"
  2493.                ENGLISH "show window ~D"
  2494.                FRANCAIS "montrer la fenΩtre ~D")
  2495.           (1+ n)
  2496. ) )
  2497. (defun M-H-doc (n)
  2498.   (format nil (DEUTSCH "Fenster Nr. ~D unsichtbar machen"
  2499.                ENGLISH "hide window ~D"
  2500.                FRANCAIS "cacher la fenΩtre ~D")
  2501.           (1+ n)
  2502. ) )
  2503.  
  2504. (bind-key #\C-F1       :control '(:TOP 0) '(C-H-doc 0))
  2505. (bind-key #\C-F2       :control '(:TOP 1) '(C-H-doc 1))
  2506. (bind-key #\C-F3       :control '(:TOP 2) '(C-H-doc 2))
  2507. (bind-key #\C-F4       :control '(:TOP 3) '(C-H-doc 3))
  2508. (bind-key #\C-F5       :control '(:TOP 4) '(C-H-doc 4))
  2509. (bind-key #\C-F6       :control '(:TOP 5) '(C-H-doc 5))
  2510. (bind-key #\C-F7       :control '(:TOP 6) '(C-H-doc 6))
  2511. (bind-key #\C-F8       :control '(:TOP 7) '(C-H-doc 7))
  2512. (bind-key #\C-F9       :control '(:TOP 8) '(C-H-doc 8))
  2513. (bind-key #\C-F10      :control '(:TOP 9) '(C-H-doc 9))
  2514.  
  2515. (bind-key #\M-H        :control '(:HELP) '(DEUTSCH "Hilfefenster (diesen Text) nach oben bringen"
  2516.                                            ENGLISH "show help window (this text)"
  2517.                                            FRANCAIS "montrer la fenΩtre d'aide (celle-ci)")
  2518. )
  2519.  
  2520. (bind-key #\C-E        :control '(:ERROR) '(DEUTSCH "Errorfenster nach oben bringen"
  2521.                                             ENGLISH "show error window"
  2522.                                             FRANCAIS "montrer la fenΩtre des erreurs")
  2523. )
  2524. (bind-key #\C-T        :control '(:TRACE) '(DEUTSCH "Tracefenster nach oben bringen"
  2525.                                             ENGLISH "show trace window"
  2526.                                             FRANCAIS "montrer la fenΩtre des traces")
  2527. )
  2528.  
  2529. (bind-key #\M-F2       :control '(:HIDE 1) '(M-H-doc 1))
  2530. (bind-key #\M-F3       :control '(:HIDE 2) '(M-H-doc 2))
  2531. (bind-key #\M-F4       :control '(:HIDE 3) '(M-H-doc 3))
  2532. (bind-key #\M-F5       :control '(:HIDE 4) '(M-H-doc 4))
  2533. (bind-key #\M-F6       :control '(:HIDE 5) '(M-H-doc 5))
  2534. (bind-key #\M-F7       :control '(:HIDE 6) '(M-H-doc 6))
  2535. (bind-key #\M-F8       :control '(:HIDE 7) '(M-H-doc 7))
  2536. (bind-key #\M-F9       :control '(:HIDE 8) '(M-H-doc 8))
  2537. (bind-key #\M-F10      :control '(:HIDE 9) '(M-H-doc 9))
  2538.  
  2539. (bind-key #\M-Q        :control '(:DELETE) '(DEUTSCH "oberes Fenster wegwerfen"
  2540.                                              ENGLISH "delete current window"
  2541.                                              FRANCAIS "enlever la fenΩtre courante")
  2542. )
  2543. (bind-key #\M-X        :control '(:LOAD) '(DEUTSCH "File laden"
  2544.                                            ENGLISH "load file"
  2545.                                            FRANCAIS "charger fichier")
  2546. )
  2547. (bind-key #\M-S        :control '(:SAVE) '(DEUTSCH "oberes Fenster abspeichern"
  2548.                                            ENGLISH "store to file"
  2549.                                            FRANCAIS "placer le contenu dans le fichier")
  2550. )
  2551. (bind-key #\M-W        :control '(:SAVE-AS) '(DEUTSCH "oberes Fenster als neues File abspeichern"
  2552.                                               ENGLISH "store to new file"
  2553.                                               FRANCAIS "placer le contenu dans un nouveau fichier")
  2554. )
  2555.  
  2556. (bind-key #\Escape     :control '(:LEAVE) '(DEUTSCH "Editor verlassen"
  2557.                                             ENGLISH "quit editor"
  2558.                                             FRANCAIS "quitter l'Θditeur")
  2559. )
  2560.  
  2561. (bind-key :string-char :writable #'insert-char)
  2562.  
  2563. ;; Ziffernblock wie gew÷hnliche Tasten behandeln, dazu Shift-Space
  2564. (dolist (c '(#\( #\) #\+ #\- #\* #\/ #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9 #\. #\,))
  2565.   (let* ((c c)
  2566.          (keypad-c (set-char-bit c :hyper t))
  2567.          (sh-keypad-c (set-char-bit c :super t)))
  2568.     (bind-key (list keypad-c sh-keypad-c)
  2569.               :writable
  2570.               #'(lambda (screen) (insert-char screen c))
  2571. ) ) )
  2572. #-DOSE (bind-key #\S-Space     :writable  #'(lambda (screen) (insert-char screen #\Space)))
  2573. #+DOSE (progn
  2574. (bind-key #\F11         :writable  #'(lambda (screen) (insert-char screen #\()))
  2575. (bind-key #\F12         :writable  #'(lambda (screen) (insert-char screen #\))))
  2576. )
  2577.  
  2578. (bind-key #\Up          :multiline 'cursor-up)
  2579. (bind-key #\Down        :multiline 'cursor-down)
  2580. (bind-key #\Left        :all       'cursor-left)
  2581. (bind-key #\Right       :all       'cursor-right)
  2582. #-DOSE (progn
  2583. (bind-key #\S-Up        :multiline 'line-up)
  2584. (bind-key #\S-Down      :multiline 'line-down)
  2585. (bind-key #\C-Up        :multiline 'page-up)
  2586. (bind-key #\C-Down      :multiline 'page-down)
  2587. (bind-key #\S-Left      :all       'cursor-to-start-of-line)
  2588. (bind-key #\S-Right     :all       'cursor-to-end-of-line)
  2589. )
  2590. #+DOSE (progn
  2591. (bind-key #\C-Up        :multiline 'line-up)
  2592. (bind-key #\C-Down      :multiline 'line-down)
  2593. (bind-key #\PgUp        :multiline 'page-up)
  2594. (bind-key #\PgDn        :multiline 'page-down)
  2595. (bind-key #\Home        :all       'cursor-to-start-of-line)
  2596. (bind-key #\End         :all       'cursor-to-end-of-line)
  2597. )
  2598.  
  2599. ; Emacs-like:
  2600. (bind-key #\C-P         :multiline 'cursor-up)
  2601. (bind-key #\C-N         :multiline 'cursor-down)
  2602. (bind-key #\C-S         :all       'cursor-left)
  2603. (bind-key #\C-D         :all       'cursor-right)
  2604. #-DOSE (progn
  2605. (bind-key #\S-C-P       :multiline 'line-up)
  2606. (bind-key #\S-C-N       :multiline 'line-down)
  2607. (bind-key #\S-C-S       :all       'cursor-to-start-of-line)
  2608. (bind-key #\S-C-D       :all       'cursor-to-end-of-line)
  2609. )
  2610.  
  2611. #+DOSE (progn
  2612. (bind-key #\C-PgUp      :multiline 'cursor-to-start-of-text)
  2613. (bind-key #\C-PgDn      :multiline 'cursor-to-end-of-text)
  2614. )
  2615.  
  2616. (bind-key #\C-B         :all       'set-block-start)
  2617. (bind-key #\C-K         :all       'set-block-end)
  2618. (bind-key #\M-B         :all       'cursor-to-start-of-block)
  2619. (bind-key #\M-K         :all       'cursor-to-end-of-block)
  2620. (bind-key #\C-H         :all       'hide-block)
  2621.  
  2622. (bind-key '(#\Return #\Enter) :and-writable-multiline 'insert-line)
  2623. (bind-key '(#\Return #\Enter) :and-writable-not-multiline 'finish)
  2624. (bind-key #\C-Y         :and-writable-multiline 'delete-line)
  2625. (bind-key #\C-J         :and-writable-multiline 'combine-lines)
  2626. (bind-key #\Delete      :writable  'delete-char)
  2627. #+DOSE (progn
  2628. (bind-key #\C-Delete    :and-writable-multiline 'delete-char-1)
  2629. (bind-key #\C-Delete    :and-writable-not-multiline 'delete-char)
  2630. )
  2631. (bind-key #\Backspace   :writable  'backspace)
  2632. #+DOSE (progn
  2633. (bind-key #\C-Backspace :and-writable-multiline 'backspace-1)
  2634. (bind-key #\C-Backspace :and-writable-not-multiline 'backspace)
  2635. )
  2636.  
  2637. ;(bind-key #\C-Space     :all       'skip-whitespace-right)
  2638. (bind-key #\C-Right     :all       'mark-next-object)
  2639. (bind-key #\C-Enter     :all       'mark-toplevel-form)
  2640. #+DOSE
  2641. (bind-key '(#\C-Return #\C-Enter) :and-writable-multiline 'eval-toplevel-form)
  2642. ;(bind-key #\C-E         :and-writable-multiline 'eval-block)
  2643. ;(bind-key #\C-E         :and-writable-multiline 'eval-buffer)
  2644.  
  2645. (bind-key #\C-X         :writable  'delete-block-buffer)
  2646. (bind-key #\C-C         :all       'copy-block-buffer)
  2647. (bind-key #\C-V         :writable  'paste-buffer)
  2648. ;(bind-key #\S-C-X       :writable  'delete-block)
  2649. ;(bind-key #\M-C         :writable  'copy-block)
  2650. ;(bind-key #\M-V         :writable  'move-block)
  2651.  
  2652. (bind-key #\Tab         :writable  'next-indent)
  2653.  
  2654. (bind-key #\C-0         :all       (set-mark-fn 0) '(set-mark-doc 0))
  2655. (bind-key #\C-1         :all       (set-mark-fn 1) '(set-mark-doc 1))
  2656. (bind-key #\C-2         :all       (set-mark-fn 2) '(set-mark-doc 2))
  2657. (bind-key #\C-3         :all       (set-mark-fn 3) '(set-mark-doc 3))
  2658. (bind-key #\C-4         :all       (set-mark-fn 4) '(set-mark-doc 4))
  2659. (bind-key #\C-5         :all       (set-mark-fn 5) '(set-mark-doc 5))
  2660. (bind-key #\C-6         :all       (set-mark-fn 6) '(set-mark-doc 6))
  2661. (bind-key #\C-7         :all       (set-mark-fn 7) '(set-mark-doc 7))
  2662. (bind-key #\C-8         :all       (set-mark-fn 8) '(set-mark-doc 8))
  2663. (bind-key #\C-9         :all       (set-mark-fn 9) '(set-mark-doc 9))
  2664. (bind-key #\M-0         :all       (cursor-to-mark-fn 0) '(cursor-to-mark-doc 0))
  2665. (bind-key #\M-1         :all       (cursor-to-mark-fn 1) '(cursor-to-mark-doc 1))
  2666. (bind-key #\M-2         :all       (cursor-to-mark-fn 2) '(cursor-to-mark-doc 2))
  2667. (bind-key #\M-3         :all       (cursor-to-mark-fn 3) '(cursor-to-mark-doc 3))
  2668. (bind-key #\M-4         :all       (cursor-to-mark-fn 4) '(cursor-to-mark-doc 4))
  2669. (bind-key #\M-5         :all       (cursor-to-mark-fn 5) '(cursor-to-mark-doc 5))
  2670. (bind-key #\M-6         :all       (cursor-to-mark-fn 6) '(cursor-to-mark-doc 6))
  2671. (bind-key #\M-7         :all       (cursor-to-mark-fn 7) '(cursor-to-mark-doc 7))
  2672. (bind-key #\M-8         :all       (cursor-to-mark-fn 8) '(cursor-to-mark-doc 8))
  2673. (bind-key #\M-9         :all       (cursor-to-mark-fn 9) '(cursor-to-mark-doc 9))
  2674.  
  2675. #+DOSE (progn
  2676. (bind-key #\M-Left      :writable  'clear-start-of-line)
  2677. (bind-key #\M-Right     :writable  'clear-end-of-line)
  2678. )
  2679.  
  2680. #+DOSE
  2681. (bind-key #\M-L         :multiline 'search-first)
  2682. (bind-key #\C-L         :multiline 'search-next)
  2683.  
  2684. )
  2685.  
  2686. #+UNIX
  2687. (progn ; noch sehr rudimentΣr und unvollstΣndig! ??
  2688.  
  2689. (defun C-H-doc (n)
  2690.   (format nil (DEUTSCH "Fenster Nr. ~D nach oben bringen"
  2691.                ENGLISH "show window ~D"
  2692.                FRANCAIS "montrer la fenΩtre ~D")
  2693.           (1+ n)
  2694. ) )
  2695.  
  2696. (bind-key #\F1         :control '(:TOP 0) '(C-H-doc 0))
  2697. (bind-key #\F2         :control '(:TOP 1) '(C-H-doc 1))
  2698. (bind-key #\F3         :control '(:TOP 2) '(C-H-doc 2))
  2699. (bind-key #\F4         :control '(:TOP 3) '(C-H-doc 3))
  2700. (bind-key #\F5         :control '(:TOP 4) '(C-H-doc 4))
  2701. (bind-key #\F6         :control '(:TOP 5) '(C-H-doc 5))
  2702. (bind-key #\F7         :control '(:TOP 6) '(C-H-doc 6))
  2703. (bind-key #\F8         :control '(:TOP 7) '(C-H-doc 7))
  2704. (bind-key #\F9         :control '(:TOP 8) '(C-H-doc 8))
  2705. (bind-key #\F10        :control '(:TOP 9) '(C-H-doc 9))
  2706.  
  2707. (bind-key #\C-G        :control '(:HELP) '(DEUTSCH "Hilfefenster (diesen Text) nach oben bringen"
  2708.                                            ENGLISH "show help window (this text)"
  2709.                                            FRANCAIS "montrer la fenΩtre d'aide (celle-ci)")
  2710. )
  2711. (bind-key #\C-E        :control '(:ERROR) '(DEUTSCH "Errorfenster nach oben bringen"
  2712.                                             ENGLISH "show error window"
  2713.                                             FRANCAIS "montrer la fenΩtre des erreurs")
  2714. )
  2715. (bind-key #\C-T        :control '(:TRACE) '(DEUTSCH "Tracefenster nach oben bringen"
  2716.                                             ENGLISH "show trace window"
  2717.                                             FRANCAIS "montrer la fenΩtre des traces")
  2718. )
  2719.  
  2720. (bind-key #\C-Q        :control '(:DELETE) '(DEUTSCH "oberes Fenster wegwerfen"
  2721.                                              ENGLISH "delete current window"
  2722.                                              FRANCAIS "enlever la fenΩtre courante")
  2723. )
  2724. (bind-key #\C-X        :control '(:LOAD) '(DEUTSCH "File laden"
  2725.                                            ENGLISH "load file"
  2726.                                            FRANCAIS "charger fichier")
  2727. )
  2728. (bind-key #\C-W        :control '(:SAVE-AS) '(DEUTSCH "oberes Fenster als neues File abspeichern"
  2729.                                               ENGLISH "store to new file"
  2730.                                               FRANCAIS "placer le contenu dans un nouveau fichier")
  2731. )
  2732.  
  2733. (bind-key '#\Escape    :control '(:LEAVE) '(DEUTSCH "Editor verlassen"
  2734.                                             ENGLISH "quit editor"
  2735.                                             FRANCAIS "quitter l'Θditeur")
  2736. )
  2737.  
  2738. (bind-key :string-char :writable #'insert-char)
  2739.  
  2740. (bind-key #\Up          :multiline 'cursor-up)
  2741. (bind-key #\Down        :multiline 'cursor-down)
  2742. (bind-key #\Left        :all       'cursor-left)
  2743. (bind-key #\Right       :all       'cursor-right)
  2744. (bind-key #\PgUp        :multiline 'page-up)
  2745. (bind-key #\PgDn        :multiline 'page-down)
  2746.  
  2747. ; Emacs-like:
  2748. (bind-key #\C-P         :multiline 'cursor-up)
  2749. (bind-key #\C-N         :multiline 'cursor-down)
  2750. (bind-key #\C-S         :all       'cursor-left)
  2751. (bind-key #\C-D         :all       'cursor-right)
  2752. (bind-key #\C-A         :all       'cursor-to-start-of-line)
  2753. (bind-key #\C-F         :all       'cursor-to-end-of-line)
  2754.  
  2755. (bind-key #\C-B         :all       'set-block-start)
  2756. (bind-key #\C-K         :all       'set-block-end)
  2757. (bind-key #\C-U         :all       'hide-block)
  2758.  
  2759. (bind-key #\Return      :and-writable-multiline 'insert-line)
  2760. (bind-key #\Return      :and-writable-not-multiline 'finish)
  2761. (bind-key #\C-Y         :and-writable-multiline 'delete-line)
  2762. (bind-key #\C-J         :and-writable-multiline 'combine-lines)
  2763. (bind-key '(#\Backspace #\Delete) :writable  'backspace)
  2764.  
  2765. (bind-key #\C-V         :all       'skip-whitespace-right)
  2766. (bind-key #\C-R         :all       'mark-next-object)
  2767. (bind-key '(#\C-O #\F11) :all      'mark-toplevel-form)
  2768. (bind-key '(#\C-L #\F12) :and-writable-multiline 'eval-toplevel-form)
  2769.  
  2770. (bind-key #\Tab         :writable  'next-indent)
  2771.  
  2772. )
  2773.  
  2774. #+AMIGA
  2775. (progn
  2776.  
  2777. (defun C-H-doc (n)
  2778.   (format nil (DEUTSCH "Fenster Nr. ~D nach oben bringen"
  2779.                ENGLISH "show window ~D"
  2780.                FRANCAIS "montrer la fenΩtre ~D")
  2781.           (1+ n)
  2782. ) )
  2783. (defun M-H-doc (n)
  2784.   (format nil (DEUTSCH "Fenster Nr. ~D unsichtbar machen"
  2785.                ENGLISH "hide window ~D"
  2786.                FRANCAIS "cacher la fenΩtre ~D")
  2787.           (1+ n)
  2788. ) )
  2789.  
  2790. (bind-key :string-char :writable #'insert-char)
  2791.  
  2792. (bind-key #\Left     :all       'cursor-left)
  2793. (bind-key #\Right    :all       'cursor-right)
  2794. (bind-key #\Down     :multiline 'cursor-down)
  2795. (bind-key #\Up       :multiline 'cursor-up)
  2796. (bind-key #\S-Left   :all       'cursor-to-start-of-line)
  2797. (bind-key #\S-Right  :all       'cursor-to-end-of-line)
  2798. (bind-key #\S-Down   :multiline 'page-down)
  2799. (bind-key #\S-Up     :multiline 'page-up)
  2800.  
  2801. (bind-key #\Code0    :all       'skip-whitespace-right) ;Null
  2802. (bind-key #\C-A      :control   '(:SAVE-AS) '(DEUTSCH "oberes Fenster als neues File abspeichern"
  2803.                                               ENGLISH "store to new file"
  2804.                                               FRANCAIS "placer le contenu dans un nouveau fichier")
  2805. )
  2806. (bind-key #\C-B       :all       'set-block-start)
  2807. ; #\C-C bleibt c-C
  2808. (bind-key #\C-D       :all       'set-block-end)
  2809. (bind-key #\C-E       :control   '(:ERROR)  '(DEUTSCH "Errorfenster nach oben bringen"
  2810.                                               ENGLISH "show error window"
  2811.                                               FRANCAIS "montrer la fenΩtre des erreurs")
  2812. )
  2813. (bind-key #\C-F       :multiline 'search-first)
  2814. ; #\C-G leer
  2815. (bind-key #\Backspace :and-writable-multiline 'backspace-1) ; #\C-H
  2816. (bind-key #\Backspace :and-writable-not-multiline 'backspace) ; #\C-H
  2817. (bind-key #\Delete    :and-writable-multiline 'delete-char-1)
  2818. (bind-key #\Delete    :and-writable-not-multiline 'delete-char)
  2819. (bind-key #\Tab       :writable  'next-indent) ; #\C-I
  2820. (bind-key #\C-J       :and-writable-multiline 'combine-lines)
  2821. (bind-key #\C-K       :writable  'clear-end-of-line)
  2822. (bind-key #\C-L       :and-writable-multiline 'eval-toplevel-form)
  2823. (bind-key #\Return    :and-writable-multiline 'insert-line) ; #\C-M
  2824. (bind-key #\Return    :and-writable-not-multiline 'finish) ; #\C-M
  2825. (bind-key #\C-N       :multiline 'search-next)
  2826. (bind-key #\C-O       :all       'mark-toplevel-form)
  2827. ; #\C-P leer
  2828. (bind-key #\C-Q       :control   '(:DELETE) '(DEUTSCH "oberes Fenster wegwerfen"
  2829.                                               ENGLISH "delete current window"
  2830.                                               FRANCAIS "enlever la fenΩtre courante")
  2831. )
  2832. (bind-key #\C-R       :all       'mark-next-object)
  2833. (bind-key #\C-S       :control   '(:SAVE) '(DEUTSCH "oberes Fenster abspeichern"
  2834.                                             ENGLISH "store to file"
  2835.                                             FRANCAIS "placer le contenu dans le fichier")
  2836. )
  2837. (bind-key #\C-T       :control   '(:TRACE) '(DEUTSCH "Tracefenster nach oben bringen"
  2838.                                              ENGLISH "show trace window"
  2839.                                              FRANCAIS "montrer la fenΩtre des traces")
  2840. )
  2841. (bind-key #\C-U       :all       'hide-block)
  2842. (bind-key #\C-V       :and-writable-multiline 'eval-block)
  2843. (bind-key #\C-W       :writable  'delete-block-buffer)
  2844. (bind-key #\C-X       :control   '(:LOAD)  '(DEUTSCH "File laden"
  2845.                                              ENGLISH "load file"
  2846.                                              FRANCAIS "charger fichier")
  2847. )
  2848. (bind-key #\C-Y       :all       'paste-buffer)
  2849. (bind-key #\C-Z       :control   '(:HIDE)  '(DEUTSCH "oberes Fenster unsichtbar machen"
  2850.                                              ENGLISH "hide top window"
  2851.                                              FRANCAIS "cacher la fenΩtre courante")
  2852. )
  2853. (bind-key '(#\Escape #\Code28) ; c-[, c-\
  2854.                       :control '(:LEAVE) '(DEUTSCH "Editor verlassen"
  2855.                                            ENGLISH "quit editor"
  2856.                                            FRANCAIS "quitter l'Θditeur")
  2857. )
  2858. (bind-key #\Code29    :control '(:TOP 0) '(C-H-doc 0)) ; c-]
  2859. ; #\Code30 = c-^ leer
  2860. ; #\Code31 = c-_ leer
  2861.  
  2862. (bind-key #\Help      :control '(:HELP) '(DEUTSCH "Hilfefenster (diesen Text) nach oben bringen"
  2863.                                           ENGLISH "show help window (this text)"
  2864.                                           FRANCAIS "montrer la fenΩtre d'aide (celle-ci)")
  2865. )
  2866.  
  2867. (bind-key #\F1        :control '(:TOP 0) '(C-H-doc 0))
  2868. (bind-key #\F2        :control '(:TOP 1) '(C-H-doc 1))
  2869. (bind-key #\F3        :control '(:TOP 2) '(C-H-doc 2))
  2870. (bind-key #\F4        :control '(:TOP 3) '(C-H-doc 3))
  2871. (bind-key #\F5        :control '(:TOP 4) '(C-H-doc 4))
  2872. (bind-key #\F6        :all     (cursor-to-mark-fn 0) '(cursor-to-mark-doc 0))
  2873. (bind-key #\F7        :all     (cursor-to-mark-fn 1) '(cursor-to-mark-doc 1))
  2874. (bind-key #\F8        :all     (cursor-to-mark-fn 2) '(cursor-to-mark-doc 2))
  2875. (bind-key #\F9        :all     (cursor-to-mark-fn 3) '(cursor-to-mark-doc 3))
  2876. (bind-key #\F10       :all     (cursor-to-mark-fn 4) '(cursor-to-mark-doc 4))
  2877. (bind-key #\S-F1      :control '(:TOP 5) '(C-H-doc 5))
  2878. (bind-key #\S-F2      :control '(:TOP 6) '(C-H-doc 6))
  2879. (bind-key #\S-F3      :control '(:TOP 7) '(C-H-doc 7))
  2880. (bind-key #\S-F4      :control '(:TOP 8) '(C-H-doc 8))
  2881. (bind-key #\S-F5      :control '(:TOP 9) '(C-H-doc 9))
  2882. (bind-key #\S-F6      :all     (set-mark-fn 0) '(set-mark-doc 0))
  2883. (bind-key #\S-F7      :all     (set-mark-fn 1) '(set-mark-doc 1))
  2884. (bind-key #\S-F8      :all     (set-mark-fn 2) '(set-mark-doc 2))
  2885. (bind-key #\S-F9      :all     (set-mark-fn 3) '(set-mark-doc 3))
  2886. (bind-key #\S-F10     :all     (set-mark-fn 4) '(set-mark-doc 4))
  2887.  
  2888. )
  2889.  
  2890. ;; *undo* behandeln ??
  2891. ;; #\C-R fⁿr Repeat ??
  2892.  
  2893. ;###############################################################################
  2894.  
  2895. ;; ob der eingebaute Editor benutzt wird:
  2896. (defparameter *use-ed* t)
  2897.  
  2898. (fmakunbound 'ed)
  2899. ; Erweiterte Version von ED in DEFS1.LSP:
  2900. (defun ed (&optional arg &aux funname sym fun def)
  2901.   (if (null arg)
  2902.     (if *use-ed*
  2903.       (edit)
  2904.       (edit-file "")
  2905.     )
  2906.     (if (or (pathnamep arg) (stringp arg))
  2907.       (if *use-ed*
  2908.         (edit `(:LOAD ,(namestring arg)))
  2909.         (edit-file arg)
  2910.       )
  2911.       (if (and (cond ((sys::function-name-p arg) (setq funname arg) t)
  2912.                      ((functionp arg) (sys::function-name-p (setq funname (sys::%record-ref arg 0))))
  2913.                      (t nil)
  2914.                )
  2915.                (fboundp (setq sym (sys::get-funname-symbol funname)))
  2916.                (or (setq fun (macro-function sym))
  2917.                    (setq fun (symbol-function sym))
  2918.                )
  2919.                (functionp fun)
  2920.                (or (sys::function-name-p arg) (eql fun arg))
  2921.                (setq def (get sym 'sys::definition))
  2922.           )
  2923.         (if *use-ed*
  2924.           (edit `(:FORM ,sym ,*package* ,(cdr def)
  2925.                         ,(write-to-string (car def) :escape t :pretty t)
  2926.           )      )
  2927.           (let ((tempfile (editor-tempfile)))
  2928.             (with-open-file (f tempfile :direction :output)
  2929.               (pprint (car def) f)
  2930.               (terpri f) (terpri f)
  2931.             )
  2932.             (let ((date (file-write-date tempfile)))
  2933.               (edit-file tempfile)
  2934.               (when (> (file-write-date tempfile) date)
  2935.                 (with-open-file (f tempfile :direction :input)
  2936.                   (let ((*package* *package*) ; *PACKAGE* binden
  2937.                         (end-of-file "EOF")) ; einmaliges Objekt
  2938.                     (loop
  2939.                       (let ((obj (read f nil end-of-file)))
  2940.                         (when (eql obj end-of-file) (return))
  2941.                         (print (evalhook obj nil nil (cdr def)))
  2942.                 ) ) ) )
  2943.                 (when (compiled-function-p fun) (compile funname))
  2944.             ) )
  2945.             funname
  2946.         ) )
  2947.         (sys::error-of-type 'error
  2948.           (DEUTSCH "~S ist nicht editierbar."
  2949.            ENGLISH "~S cannot be edited."
  2950.            FRANCAIS "~S ne peut pas Ωtre ΘditΘ.")
  2951.           arg
  2952. ) ) ) ) )
  2953.  
  2954.